Skip to content
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
5 changes: 5 additions & 0 deletions src/ReplayReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ ReplayReader::ReplayReader()
numOrders = 0;
stepsUntilNextOrder = -1;
wideStepCounter = false;
versionMinor = VERSION_MINOR;
checksum = 0;
}

Expand Down Expand Up @@ -89,6 +90,8 @@ bool ReplayReader::loadReplay(GAGCore::InputStream *inputStream, bool skipToOrde
// Replays written before version 87 store step counters as Uint16
wideStepCounter = (version_minor >= REPLAY_UINT32_STEP_COUNTER_VERSION_MINOR);

versionMinor = version_minor;

// If there are no orders, this is also not a valid replay (there should be at least a NullOrder)
if (stream->isEndOfStream())
{
Expand All @@ -112,6 +115,7 @@ bool ReplayReader::loadReplay(GAGCore::InputStream *inputStream, bool skipToOrde
{
// Read an order from the stream
NetSendOrder msg;
msg.setDecodeVersionMinor(versionMinor);
msg.decodeData(stream);
order = msg.getOrder();

Expand Down Expand Up @@ -213,6 +217,7 @@ std::shared_ptr<Order> ReplayReader::retrieveOrder()
{
// Read the order from the stream
NetSendOrder msg;
msg.setDecodeVersionMinor(versionMinor);
msg.decodeData(stream);
order = msg.getOrder();

Expand Down
3 changes: 3 additions & 0 deletions src/ReplayReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ class ReplayReader
/// (format version >= REPLAY_UINT32_STEP_COUNTER_VERSION_MINOR)
bool wideStepCounter;

/// Format version from the replay header, used to decode orders.
Uint32 versionMinor;

/// The game's current checksum (or 0 if it's not given)
Uint32 checksum;
};
9 changes: 8 additions & 1 deletion src/net/message/OrderMessages.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@ using namespace GAGCore;

NetSendOrder::NetSendOrder()
{
decodeVersionMinor=VERSION_MINOR;
}

NetSendOrder::NetSendOrder(std::shared_ptr<Order> newOrder)
{
order=newOrder;
decodeVersionMinor=VERSION_MINOR;
}

void NetSendOrder::setDecodeVersionMinor(Uint32 newVersionMinor)
{
decodeVersionMinor=newVersionMinor;
}

void NetSendOrder::changeOrder(std::shared_ptr<Order> newOrder)
Expand Down Expand Up @@ -66,7 +73,7 @@ void NetSendOrder::decodeData(GAGCore::InputStream* stream)
stream->read(buffer.data(), size, "data");
stream->readLeaveSection();

order = Order::getOrder(buffer.data(), size, VERSION_MINOR);
order = Order::getOrder(buffer.data(), size, decodeVersionMinor);

// If this couldn't be interpreted return it returned a NULL order, so we throw.
if (order == std::shared_ptr<Order>())
Expand Down
7 changes: 7 additions & 0 deletions src/net/message/OrderMessages.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ class NetSendOrder : public NetMessage

void changeOrder(std::shared_ptr<Order> newOrder);

/// Sets the version used by subsequent decodeData() calls.
/// Defaults to VERSION_MINOR; replay readers supply their header version.
/// Does not affect encoding.
void setDecodeVersionMinor(Uint32 newVersionMinor);

Uint8 getMessageType() const;
void encodeData(GAGCore::OutputStream* stream) const;
/// Wire format: Uint32 size | size bytes payload | Uint8 sender | Uint32 checksum.
Expand All @@ -49,6 +54,8 @@ class NetSendOrder : public NetMessage
bool operator==(const NetMessage& rhs) const;
private:
std::shared_ptr<Order> order;

Uint32 decodeVersionMinor;
};

/// Latency probe sent periodically to measure round-trip time.
Expand Down
39 changes: 38 additions & 1 deletion test/ReplayStepCounterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,13 @@ class StepTestOrder : public MiscOrder
Uint8 getOrderType(void) { return ORDER_DELETE; }
};

std::shared_ptr<Order> Order::getOrder(const Uint8 *netData, int netDataLength, Uint32 /*versionMinor*/)
// Record the requested version because supported replay versions currently
// decode identically.
Uint32 lastDecodeVersionMinor = 0;

std::shared_ptr<Order> Order::getOrder(const Uint8 *netData, int netDataLength, Uint32 versionMinor)
{
lastDecodeVersionMinor = versionMinor;
if (netDataLength < 1 || netData == NULL)
return std::shared_ptr<Order>();
if (netData[0] == ORDER_NULL)
Expand Down Expand Up @@ -257,13 +262,45 @@ void testVersionBounds()
}
}

// 4. Both the initial scan and playback use the replay header version.
void testDecodeVersionPlumbing()
{
const Uint16 oldVersion = REPLAY_MINIMUM_VERSION_MINOR;

// Require an older version so a hardcoded VERSION_MINOR cannot pass.
check(oldVersion != VERSION_MINOR,
"decodeVersion: replay floor is below the current build version");

ReplayReader reader;
const bool wideCounters = oldVersion >= REPLAY_UINT32_STEP_COUNTER_VERSION_MINOR;
lastDecodeVersionMinor = 0;
bool loaded = reader.loadReplay(writeReplayBody(oldVersion, wideCounters, 7), false);
check(loaded, "decodeVersion: old-but-supported replay loads");
if (!loaded)
return;

check(lastDecodeVersionMinor == oldVersion,
"decodeVersion: initial scan uses the replay header version");

// Reset the recorder to check playback independently of the initial scan.
lastDecodeVersionMinor = 0;

for (Uint32 i = 0; i < 7; i++)
reader.advanceStep();
std::shared_ptr<Order> order = reader.retrieveOrder();
check(order && order->getOrderType() == ORDER_DELETE, "decodeVersion: order read back");
check(lastDecodeVersionMinor == oldVersion,
"decodeVersion: order decoded against the replay's version, not VERSION_MINOR");
}

} // namespace

int main(int /*argc*/, char* /*argv*/[])
{
testWideRoundTrip();
testOldFormatUint16();
testVersionBounds();
testDecodeVersionPlumbing();
std::printf(failures == 0 ? "ALL PASS\n" : "FAILURES: %d\n", failures);
return failures == 0 ? 0 : 1;
}
Loading