test: cover testSpawning
This commit is contained in:
1 parent
4c63023aea
commit
832d5f6b8b
1 file changed
+158
@@ -156,3 +156,161 @@ VF_TEST(aNocturnalRuleIsRefusedInBroadDaylight) {
|
|||||||
SpawnDenial::WrongTimeOfDay);
|
SpawnDenial::WrongTimeOfDay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VF_TEST(theWrongBlockUnderfootIsRefused) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
SpawnRule rule = zombieRule();
|
||||||
|
rule.groundBlocks = {Block::Sand};
|
||||||
|
CHECK(checkSpawnRule(rule, env, originCell(), MobCap{}) == SpawnDenial::UnsuitableGround);
|
||||||
|
|
||||||
|
rule.groundBlocks = {Block::Sand, Block::Grass};
|
||||||
|
CHECK(checkSpawnRule(rule, env, originCell(), MobCap{}) == SpawnDenial::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aCeilingPressedOntoTheSpawnCellIsRefusedForNoHeadroom) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
world.setBlock(0, spawnY + 1, 0, Block::Stone);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
CHECK(checkSpawnRule(zombieRule(), env, originCell(), MobCap{}) == SpawnDenial::NoHeadroom);
|
||||||
|
|
||||||
|
SpawnRule crawler = zombieRule();
|
||||||
|
crawler.requiredHeadroom = 1;
|
||||||
|
CHECK(checkSpawnRule(crawler, env, originCell(), MobCap{}) == SpawnDenial::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aTorchLitCellIsRefusedForTooMuchBlockLight) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
world.setBlock(1, spawnY, 1, Block::Glowstone);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
CHECK(env.blockLightAt(originCell()) > zombieRule().maxBlockLight);
|
||||||
|
CHECK(checkSpawnRule(zombieRule(), env, originCell(), MobCap{}) ==
|
||||||
|
SpawnDenial::BlockLightTooHigh);
|
||||||
|
|
||||||
|
// The same cell far from the emitter is dark enough again.
|
||||||
|
Vec3i faraway{30, spawnY, 30};
|
||||||
|
CHECK_EQ(env.blockLightAt(faraway), 0);
|
||||||
|
CHECK(checkSpawnRule(zombieRule(), env, faraway, MobCap{}) == SpawnDenial::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(anOpenSkyAtNoonIsRefusedForTooMuchSkyLight) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
env.daytime = true;
|
||||||
|
|
||||||
|
SpawnRule daywalker = zombieRule();
|
||||||
|
daywalker.dayAllowed = true;
|
||||||
|
CHECK_EQ(env.skyLightAt(originCell()), 15);
|
||||||
|
CHECK(checkSpawnRule(daywalker, env, originCell(), MobCap{}) ==
|
||||||
|
SpawnDenial::SkyLightTooHigh);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aSunlessCellIsRefusedForTooLittleLight) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
for (int x = -fieldSpan; x <= fieldSpan; ++x) {
|
||||||
|
for (int z = -fieldSpan; z <= fieldSpan; ++z) world.setBlock(x, floorY + 4, z, Block::Stone);
|
||||||
|
}
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
env.daytime = true;
|
||||||
|
env.playerPosition = {20.5f, static_cast<float>(spawnY), 0.5f};
|
||||||
|
|
||||||
|
CHECK_EQ(env.skyLightAt(originCell()), 0);
|
||||||
|
CHECK(checkSpawnRule(sheepRule(), env, originCell(), MobCap{}) == SpawnDenial::LightTooLow);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theSpawnRingAroundThePlayerIsRefusedOnBothSides) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
env.playerPosition = {0.5f, static_cast<float>(spawnY), 0.5f};
|
||||||
|
CHECK(checkSpawnRule(zombieRule(), env, originCell(), MobCap{}) ==
|
||||||
|
SpawnDenial::TooCloseToPlayer);
|
||||||
|
|
||||||
|
env.playerPosition = {400.5f, static_cast<float>(spawnY), 0.5f};
|
||||||
|
CHECK(checkSpawnRule(zombieRule(), env, originCell(), MobCap{}) ==
|
||||||
|
SpawnDenial::TooFarFromPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aColumnWithNoFloorReportsThatNoCellWasStandable) {
|
||||||
|
World world;
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
Vec3i cell;
|
||||||
|
CHECK(!pickSpawnCell(env, Vec3i{0, 0, 0}, 99u, 0, cell));
|
||||||
|
|
||||||
|
Spawner spawner;
|
||||||
|
SpawnResult result = spawner.runColumn(env, SpawnCategory::Hostile, Vec3i{0, 0, 0}, 99u, 0);
|
||||||
|
CHECK(result.denial == SpawnDenial::NoStandableCell);
|
||||||
|
CHECK(!result.spawned);
|
||||||
|
CHECK_EQ(spawner.denialCount(SpawnDenial::NoStandableCell), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aCategoryWithNoRulesReportsThatNoRuleMatched) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
|
||||||
|
Spawner spawner;
|
||||||
|
SpawnResult result = spawner.runColumn(env, SpawnCategory::Water, Vec3i{0, 0, 0}, 7u, 0);
|
||||||
|
CHECK(result.denial == SpawnDenial::NoRuleMatched);
|
||||||
|
CHECK_EQ(spawner.denialCount(SpawnDenial::NoRuleMatched), 1);
|
||||||
|
|
||||||
|
// Adding one water rule is all it takes for the category to come alive.
|
||||||
|
std::vector<SpawnRule> rules = defaultSpawnRules();
|
||||||
|
SpawnRule diver = sheepRule();
|
||||||
|
diver.category = SpawnCategory::Water;
|
||||||
|
rules.push_back(diver);
|
||||||
|
Spawner wet(rules);
|
||||||
|
CHECK(wet.pickRule(env, SpawnCategory::Water, 3u) != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(theMobCapGrowsWithTheNumberOfLoadedChunks) {
|
||||||
|
MobCap cap;
|
||||||
|
CHECK_EQ(cap.capFor(SpawnCategory::Hostile, 289), cap.baseCapFor(SpawnCategory::Hostile));
|
||||||
|
CHECK_EQ(cap.capFor(SpawnCategory::Hostile, 578), cap.baseCapFor(SpawnCategory::Hostile) * 2);
|
||||||
|
CHECK_EQ(cap.capFor(SpawnCategory::Hostile, 0), 0);
|
||||||
|
|
||||||
|
int previous = -1;
|
||||||
|
for (int chunks = 0; chunks <= 1156; chunks += 17) {
|
||||||
|
int current = cap.capFor(SpawnCategory::Hostile, chunks);
|
||||||
|
CHECK(current >= previous);
|
||||||
|
previous = current;
|
||||||
|
}
|
||||||
|
CHECK(cap.capFor(SpawnCategory::Hostile, 1156) > cap.capFor(SpawnCategory::Hostile, 289));
|
||||||
|
CHECK(cap.capFor(SpawnCategory::Passive, 289) < cap.capFor(SpawnCategory::Hostile, 289));
|
||||||
|
|
||||||
|
// A quarter of the world loaded holds roughly a quarter of the mobs.
|
||||||
|
CHECK_EQ(cap.capFor(SpawnCategory::Hostile, 72), 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
VF_TEST(aRunningCycleStopsSpawningOnceTheCapIsReached) {
|
||||||
|
World world = plateWorld(Block::Grass);
|
||||||
|
LightField light = bakeLight(world);
|
||||||
|
SpawnEnvironment env = nightEnvironment(world, light);
|
||||||
|
env.loadedChunks = 17;
|
||||||
|
env.playerPosition = {0.5f, static_cast<float>(spawnY), 0.5f};
|
||||||
|
|
||||||
|
MobCap cap;
|
||||||
|
int limit = cap.capFor(SpawnCategory::Hostile, env.loadedChunks);
|
||||||
|
CHECK(limit > 0);
|
||||||
|
|
||||||
|
std::vector<Vec3i> columns;
|
||||||
|
for (int cx = -2; cx <= 2; ++cx) {
|
||||||
|
for (int cz = -2; cz <= 2; ++cz) columns.push_back(Vec3i{cx, 0, cz});
|
||||||
|
}
|
||||||
|
|
||||||
|
Spawner spawner;
|
||||||
|
spawner.setAttemptsPerColumn(6);
|
||||||
|
for (int cycle = 0; cycle < 12; ++cycle) {
|
||||||
|
spawner.runCycle(env, SpawnCategory::Hostile, columns, 1234u + static_cast<uint64_t>(cycle));
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user