Skip to content

[GEN][ZH] Fix replay header mismatch between builds using 32 bit or 64 bit wide time_t #765

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

Merged
merged 3 commits into from
Apr 28, 2025
Merged
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
30 changes: 21 additions & 9 deletions Generals/Code/GameEngine/Source/Common/Recorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,17 @@ Int REPLAY_CRC_INTERVAL = 100;
const char *replayExtention = ".rep";
const char *lastReplayFileName = "00000000"; // a name the user is unlikely to ever type, but won't cause panic & confusion

// TheSuperHackers @tweak helmutbuhler 25/04/2025
// The replay header contains two time fields; startTime and endTime of type time_t.
// time_t is 32 bit wide on VC6, but on newer compilers it is 64 bit wide.
// In order to remain compatible we need to load and save time values with 32 bits.
// Note that this will overflow on January 18, 2038. @todo Upgrade to 64 bits when we break compatibility.
typedef int32_t replay_time_t;

static time_t startTime;
static const UnsignedInt startTimeOffset = 6;
static const UnsignedInt endTimeOffset = startTimeOffset + sizeof(time_t);
static const UnsignedInt framesOffset = endTimeOffset + sizeof(time_t);
static const UnsignedInt endTimeOffset = startTimeOffset + sizeof(replay_time_t);
static const UnsignedInt framesOffset = endTimeOffset + sizeof(replay_time_t);
static const UnsignedInt desyncOffset = framesOffset + sizeof(UnsignedInt);
static const UnsignedInt quitEarlyOffset = desyncOffset + sizeof(Bool);
static const UnsignedInt disconOffset = quitEarlyOffset + sizeof(Bool);
Expand All @@ -75,7 +82,8 @@ void RecorderClass::logGameStart(AsciiString options)
if (!fseek(m_file, startTimeOffset, SEEK_SET))
{
// save off start time
fwrite(&startTime, sizeof(time_t), 1, m_file);
replay_time_t tmp = (replay_time_t)startTime;
fwrite(&tmp, sizeof(replay_time_t), 1, m_file);
}
// move back to end of stream
#ifdef DEBUG_CRASHING
Expand Down Expand Up @@ -229,7 +237,8 @@ void RecorderClass::logGameEnd( void )
if (!fseek(m_file, endTimeOffset, SEEK_SET))
{
// save off end time
fwrite(&t, sizeof(time_t), 1, m_file);
replay_time_t tmp = (replay_time_t)t;
fwrite(&tmp, sizeof(replay_time_t), 1, m_file);
}
// move to appropriate offset
if (!fseek(m_file, framesOffset, SEEK_SET))
Expand Down Expand Up @@ -555,9 +564,9 @@ void RecorderClass::startRecording(GameDifficulty diff, Int originalGameMode, In
//
// **** if this changes, change the LAN Playtest code above ****
//
time_t t = 0;
fwrite(&t, sizeof(time_t), 1, m_file); // reserve space for start time
fwrite(&t, sizeof(time_t), 1, m_file); // reserve space for end time
replay_time_t t = 0;
fwrite(&t, sizeof(replay_time_t), 1, m_file); // reserve space for start time
fwrite(&t, sizeof(replay_time_t), 1, m_file); // reserve space for end time

UnsignedInt frames = 0;
fwrite(&frames, sizeof(UnsignedInt), 1, m_file); // reserve space for duration in frames
Expand Down Expand Up @@ -834,8 +843,11 @@ Bool RecorderClass::readReplayHeader(ReplayHeader& header)
}

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

fread(&header.frameDuration, sizeof(UnsignedInt), 1, m_file);

Expand Down
30 changes: 21 additions & 9 deletions GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,17 @@ Int REPLAY_CRC_INTERVAL = 100;
const char *replayExtention = ".rep";
const char *lastReplayFileName = "00000000"; // a name the user is unlikely to ever type, but won't cause panic & confusion

// TheSuperHackers @tweak helmutbuhler 25/04/2025
// The replay header contains two time fields; startTime and endTime of type time_t.
// time_t is 32 bit wide on VC6, but on newer compilers it is 64 bit wide.
// In order to remain compatible we need to load and save time values with 32 bits.
// Note that this will overflow on January 18, 2038. @todo Upgrade to 64 bits when we break compatibility.
typedef int32_t replay_time_t;

static time_t startTime;
static const UnsignedInt startTimeOffset = 6;
static const UnsignedInt endTimeOffset = startTimeOffset + sizeof(time_t);
static const UnsignedInt framesOffset = endTimeOffset + sizeof(time_t);
static const UnsignedInt endTimeOffset = startTimeOffset + sizeof(replay_time_t);
static const UnsignedInt framesOffset = endTimeOffset + sizeof(replay_time_t);
static const UnsignedInt desyncOffset = framesOffset + sizeof(UnsignedInt);
static const UnsignedInt quitEarlyOffset = desyncOffset + sizeof(Bool);
static const UnsignedInt disconOffset = quitEarlyOffset + sizeof(Bool);
Expand All @@ -75,7 +82,8 @@ void RecorderClass::logGameStart(AsciiString options)
if (!fseek(m_file, startTimeOffset, SEEK_SET))
{
// save off start time
fwrite(&startTime, sizeof(time_t), 1, m_file);
replay_time_t tmp = (replay_time_t)startTime;
fwrite(&tmp, sizeof(replay_time_t), 1, m_file);
}
// move back to end of stream
#ifdef DEBUG_CRASHING
Expand Down Expand Up @@ -229,7 +237,8 @@ void RecorderClass::logGameEnd( void )
if (!fseek(m_file, endTimeOffset, SEEK_SET))
{
// save off end time
fwrite(&t, sizeof(time_t), 1, m_file);
replay_time_t tmp = (replay_time_t)t;
fwrite(&tmp, sizeof(replay_time_t), 1, m_file);
}
// move to appropriate offset
if (!fseek(m_file, framesOffset, SEEK_SET))
Expand Down Expand Up @@ -557,9 +566,9 @@ void RecorderClass::startRecording(GameDifficulty diff, Int originalGameMode, In
//
// **** if this changes, change the LAN code above ****
//
time_t t = 0;
fwrite(&t, sizeof(time_t), 1, m_file); // reserve space for start time
fwrite(&t, sizeof(time_t), 1, m_file); // reserve space for end time
replay_time_t t = 0;
fwrite(&t, sizeof(replay_time_t), 1, m_file); // reserve space for start time
fwrite(&t, sizeof(replay_time_t), 1, m_file); // reserve space for end time

UnsignedInt frames = 0;
fwrite(&frames, sizeof(UnsignedInt), 1, m_file); // reserve space for duration in frames
Expand Down Expand Up @@ -836,8 +845,11 @@ Bool RecorderClass::readReplayHeader(ReplayHeader& header)
}

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

fread(&header.frameDuration, sizeof(UnsignedInt), 1, m_file);

Expand Down
Loading