test: extend coverage of testNetSession
This commit is contained in:
1 parent
5a665a3dd9
commit
58ed476d43
1 file changed
+159
@@ -310,3 +310,162 @@ VF_TEST(theClientWorldMirrorsTheServerByteForByteAcrossAnUnreliableLink) {
|
|||||||
|
|
||||||
pair.client.beginHandshake("vulp", 1, 2);
|
pair.client.beginHandshake("vulp", 1, 2);
|
||||||
|
|
||||||
|
Lcg rng(0x2ee9d1);
|
||||||
|
const Block palette[4] = {Block::Glowstone, Block::Obsidian, Block::Ice, Block::Planks};
|
||||||
|
uint64_t tick = 0;
|
||||||
|
for (; tick < 400; ++tick) {
|
||||||
|
if (pair.server.phase() == SessionPhase::Play && tick % 3 == 0) {
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
int gx = rng.range(32) - 16;
|
||||||
|
int gz = rng.range(32) - 16;
|
||||||
|
int gy = rng.range(14);
|
||||||
|
pair.edit(gx, gy, gz, palette[rng.range(4)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pair.step(tick);
|
||||||
|
pair.clearDirty();
|
||||||
|
}
|
||||||
|
// Editing stops; the link is given time to finish retransmitting the tail.
|
||||||
|
for (; tick < 600; ++tick) {
|
||||||
|
pair.step(tick);
|
||||||
|
pair.clearDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(pair.server.phase() == SessionPhase::Play);
|
||||||
|
CHECK(pair.client.phase() == SessionPhase::Play);
|
||||||
|
CHECK(pair.link.droppedCount() > 50u);
|
||||||
|
CHECK(pair.serverTransport.stats().retransmitted > 0u);
|
||||||
|
|
||||||
|
std::vector<Vec3i> coords = sortedCoords(pair.server.view().sent);
|
||||||
|
CHECK_EQ(coords.size(), static_cast<std::size_t>(13));
|
||||||
|
CHECK_EQ(worldDigest(pair.serverWorld, coords), worldDigest(pair.clientWorld, coords));
|
||||||
|
|
||||||
|
// A digest that ignores content would pass anything: break one block and it
|
||||||
|
// must disagree.
|
||||||
|
pair.clientWorld.setBlock(0, 0, 0, Block::Bedrock);
|
||||||
|
CHECK(worldDigest(pair.serverWorld, coords) != worldDigest(pair.clientWorld, coords));
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(entityPositionsRideTheUnreliableChannelAndOnlyTheNewestSurvives) {
|
||||||
|
LinkQuality quality;
|
||||||
|
quality.latencyTicks = 1;
|
||||||
|
quality.seed = 0x77777777ull;
|
||||||
|
TransportConfig transportConfig;
|
||||||
|
Pair pair(quality, transportConfig, quietConfig());
|
||||||
|
|
||||||
|
pair.client.beginHandshake("vulp", 1, 2);
|
||||||
|
for (uint64_t tick = 0; tick < 10; ++tick) pair.step(tick);
|
||||||
|
CHECK(pair.client.phase() == SessionPhase::Play);
|
||||||
|
|
||||||
|
for (uint64_t tick = 10; tick < 60; ++tick) {
|
||||||
|
float progress = static_cast<float>(tick - 10);
|
||||||
|
pair.server.sendEntityMove(42, Vec3{progress, 64.0f, -progress}, 0.5f, -0.25f, true);
|
||||||
|
pair.step(tick);
|
||||||
|
}
|
||||||
|
for (uint64_t tick = 60; tick < 70; ++tick) pair.step(tick);
|
||||||
|
|
||||||
|
EntityMove seen;
|
||||||
|
CHECK(pair.client.entityMove(42, seen));
|
||||||
|
CHECK_NEAR(seen.x, 49.0f, 0.001f);
|
||||||
|
CHECK_NEAR(seen.z, -49.0f, 0.001f);
|
||||||
|
CHECK_NEAR(seen.yaw, 0.5f, 0.001f);
|
||||||
|
CHECK(seen.onGround);
|
||||||
|
CHECK_EQ(pair.client.trackedEntityCount(), static_cast<std::size_t>(1));
|
||||||
|
CHECK_EQ(pair.server.stats().entityMovesSent, static_cast<uint64_t>(50));
|
||||||
|
CHECK_EQ(pair.serverTransport.stats().retransmitted, static_cast<uint64_t>(0));
|
||||||
|
|
||||||
|
EntityMove missing;
|
||||||
|
CHECK(!pair.client.entityMove(43, missing));
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aPlayerStateReportMovesTheServerSideViewAndStreamsTheNewChunks) {
|
||||||
|
LinkQuality quality;
|
||||||
|
quality.latencyTicks = 1;
|
||||||
|
TransportConfig transportConfig;
|
||||||
|
SessionConfig config = quietConfig();
|
||||||
|
config.viewRadius = 1;
|
||||||
|
config.chunksPerTick = 4;
|
||||||
|
Pair pair(quality, transportConfig, config);
|
||||||
|
buildTerrain(pair.serverWorld, 4);
|
||||||
|
|
||||||
|
pair.client.beginHandshake("vulp", 1, 2);
|
||||||
|
for (uint64_t tick = 0; tick < 30; ++tick) pair.step(tick);
|
||||||
|
CHECK(pair.server.view().centreChunk == Vec3i(0, 0, 0));
|
||||||
|
// Radius 1 is a 7-slot sphere; five of those slots sit in the y = 0 plane.
|
||||||
|
std::size_t nearOrigin = pair.server.view().sent.size();
|
||||||
|
CHECK_EQ(nearOrigin, static_cast<std::size_t>(5));
|
||||||
|
|
||||||
|
PlayerState moved;
|
||||||
|
moved.x = 40.0f;
|
||||||
|
moved.y = 8.0f;
|
||||||
|
moved.z = 40.0f;
|
||||||
|
moved.health = 20.0f;
|
||||||
|
pair.client.sendPlayerState(moved);
|
||||||
|
for (uint64_t tick = 30; tick < 70; ++tick) pair.step(tick);
|
||||||
|
|
||||||
|
CHECK(pair.server.view().centreChunk == Vec3i(2, 0, 2));
|
||||||
|
CHECK(pair.server.view().hasChunk(Vec3i{2, 0, 2}));
|
||||||
|
CHECK(!pair.server.view().hasChunk(Vec3i{0, 0, 0}));
|
||||||
|
CHECK(!pair.server.view().tracker.contains(Vec3i{0, 0, 0}));
|
||||||
|
CHECK_NEAR(pair.server.view().position.x, 40.0f, 0.001f);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aClientBlockEditTravelsUpstreamAndComesBackAsAConfirmedChange) {
|
||||||
|
LinkQuality quality;
|
||||||
|
quality.lossPercent = 20;
|
||||||
|
quality.latencyTicks = 1;
|
||||||
|
quality.seed = 0x31415926ull;
|
||||||
|
TransportConfig transportConfig;
|
||||||
|
transportConfig.retransmitTimeoutTicks = 6;
|
||||||
|
Pair pair(quality, transportConfig, quietConfig());
|
||||||
|
buildTerrain(pair.serverWorld, 1);
|
||||||
|
|
||||||
|
pair.client.beginHandshake("vulp", 1, 2);
|
||||||
|
for (uint64_t tick = 0; tick < 40; ++tick) pair.step(tick);
|
||||||
|
CHECK(pair.server.view().hasChunk(Vec3i{0, 0, 0}));
|
||||||
|
CHECK(pair.clientWorld.blockAt(3, 15, 4) == Block::Air);
|
||||||
|
|
||||||
|
pair.client.requestBlockEdit(3, 15, 4, Block::Glowstone);
|
||||||
|
|
||||||
|
for (uint64_t tick = 40; tick < 90; ++tick) {
|
||||||
|
pair.server.receive(tick);
|
||||||
|
for (const BlockChange& edit : pair.server.requestedEdits())
|
||||||
|
pair.edit(edit.x, edit.y, edit.z, edit.block);
|
||||||
|
pair.server.clearRequestedEdits();
|
||||||
|
pair.server.send(tick);
|
||||||
|
pair.clearDirty();
|
||||||
|
pair.client.receive(tick);
|
||||||
|
pair.client.send(tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(pair.serverWorld.blockAt(3, 15, 4) == Block::Glowstone);
|
||||||
|
CHECK(pair.clientWorld.blockAt(3, 15, 4) == Block::Glowstone);
|
||||||
|
CHECK_EQ(pair.client.stats().blockChangesApplied, static_cast<uint64_t>(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(viewTrackerReportsOnlyTheDifferenceWhenTheCentreMoves) {
|
||||||
|
ViewTracker tracker(2);
|
||||||
|
std::vector<Vec3i> entered;
|
||||||
|
std::vector<Vec3i> left;
|
||||||
|
|
||||||
|
tracker.update(Vec3i{0, 0, 0}, entered, left);
|
||||||
|
CHECK_EQ(entered.size(), static_cast<std::size_t>(33));
|
||||||
|
CHECK_EQ(left.size(), static_cast<std::size_t>(0));
|
||||||
|
CHECK(entered[0] == Vec3i(0, 0, 0));
|
||||||
|
CHECK(tracker.contains(Vec3i{0, 0, 2}));
|
||||||
|
CHECK(!tracker.contains(Vec3i{2, 2, 0}));
|
||||||
|
CHECK_EQ(tracker.size(), static_cast<std::size_t>(33));
|
||||||
|
|
||||||
|
std::size_t previous = tracker.size();
|
||||||
|
tracker.update(Vec3i{1, 0, 0}, entered, left);
|
||||||
|
CHECK(entered.size() < previous);
|
||||||
|
CHECK(entered.size() > 0u);
|
||||||
|
CHECK_EQ(entered.size(), left.size());
|
||||||
|
CHECK_EQ(tracker.size(), previous);
|
||||||
|
for (const Vec3i& coord : entered) CHECK(tracker.contains(coord));
|
||||||
|
for (const Vec3i& coord : left) CHECK(!tracker.contains(coord));
|
||||||
|
|
||||||
|
tracker.update(Vec3i{40, 0, 40}, entered, left);
|
||||||
|
CHECK_EQ(entered.size(), static_cast<std::size_t>(33));
|
||||||
|
CHECK_EQ(left.size(), static_cast<std::size_t>(33));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user