From d8d1e6e1d2f668cb7b34eae7484e59e2310e847a Mon Sep 17 00:00:00 2001 From: Mattes D Date: Mon, 2 Sep 2019 06:46:40 +0200 Subject: Added a BasicGeneratorTest. --- src/Generating/ChunkDesc.cpp | 8 +- src/Generating/ChunkDesc.h | 8 +- tests/Generating/BasicGeneratorTest.cpp | 223 ++++++++++++++++++++++++++++++++ tests/Generating/CMakeLists.txt | 30 +++++ tests/Generating/Stubs.cpp | 72 +++++++++++ tests/TestHelpers.h | 12 +- 6 files changed, 344 insertions(+), 9 deletions(-) create mode 100644 tests/Generating/BasicGeneratorTest.cpp diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp index 18947f401..1aecb83be 100644 --- a/src/Generating/ChunkDesc.cpp +++ b/src/Generating/ChunkDesc.cpp @@ -87,7 +87,7 @@ void cChunkDesc::SetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Bl -BLOCKTYPE cChunkDesc::GetBlockType(int a_RelX, int a_RelY, int a_RelZ) +BLOCKTYPE cChunkDesc::GetBlockType(int a_RelX, int a_RelY, int a_RelZ) const { return cChunkDef::GetBlock(m_BlockArea.GetBlockTypes(), a_RelX, a_RelY, a_RelZ); } @@ -96,7 +96,7 @@ BLOCKTYPE cChunkDesc::GetBlockType(int a_RelX, int a_RelY, int a_RelZ) -NIBBLETYPE cChunkDesc::GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ) +NIBBLETYPE cChunkDesc::GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ) const { return m_BlockArea.GetRelBlockMeta(a_RelX, a_RelY, a_RelZ); } @@ -123,7 +123,7 @@ void cChunkDesc::SetBiome(int a_RelX, int a_RelZ, EMCSBiome a_BiomeID) -EMCSBiome cChunkDesc::GetBiome(int a_RelX, int a_RelZ) +EMCSBiome cChunkDesc::GetBiome(int a_RelX, int a_RelZ) const { return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); } @@ -141,7 +141,7 @@ void cChunkDesc::SetHeight(int a_RelX, int a_RelZ, HEIGHTTYPE a_Height) -HEIGHTTYPE cChunkDesc::GetHeight(int a_RelX, int a_RelZ) +HEIGHTTYPE cChunkDesc::GetHeight(int a_RelX, int a_RelZ) const { return cChunkDef::GetHeight(m_HeightMap, a_RelX, a_RelZ); } diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h index 997b640a3..b813a88aa 100644 --- a/src/Generating/ChunkDesc.h +++ b/src/Generating/ChunkDesc.h @@ -65,18 +65,18 @@ public: // tolua_begin void SetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType); - BLOCKTYPE GetBlockType(int a_RelX, int a_RelY, int a_RelZ); + BLOCKTYPE GetBlockType(int a_RelX, int a_RelY, int a_RelZ) const; void SetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockMeta); - NIBBLETYPE GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ); + NIBBLETYPE GetBlockMeta(int a_RelX, int a_RelY, int a_RelZ) const; void SetBiome(int a_RelX, int a_RelZ, EMCSBiome a_BiomeID); - EMCSBiome GetBiome(int a_RelX, int a_RelZ); + EMCSBiome GetBiome(int a_RelX, int a_RelZ) const; // These operate on the heightmap, so they could get out of sync with the data // Use UpdateHeightmap() to re-calculate heightmap from the block data void SetHeight(int a_RelX, int a_RelZ, HEIGHTTYPE a_Height); - HEIGHTTYPE GetHeight(int a_RelX, int a_RelZ); + HEIGHTTYPE GetHeight(int a_RelX, int a_RelZ) const; // tolua_end diff --git a/tests/Generating/BasicGeneratorTest.cpp b/tests/Generating/BasicGeneratorTest.cpp new file mode 100644 index 000000000..0f807038c --- /dev/null +++ b/tests/Generating/BasicGeneratorTest.cpp @@ -0,0 +1,223 @@ +#include "Globals.h" +#include "Generating/ChunkGenerator.h" +#include "Generating/ChunkDesc.h" +#include "../TestHelpers.h" +#include "IniFile.h" + + + + + +/** Checks that the chunk's heightmap corresponds to the chunk contents. */ +static void verifyChunkDescHeightmap(const cChunkDesc & a_ChunkDesc) +{ + for (int x = 0; x < cChunkDef::Width; x++) + { + for (int z = 0; z < cChunkDef::Width; z++) + { + for (int y = cChunkDef::Height - 1; y > 0; y--) + { + BLOCKTYPE BlockType = a_ChunkDesc.GetBlockType(x, y, z); + if (BlockType != E_BLOCK_AIR) + { + int Height = a_ChunkDesc.GetHeight(x, z); + TEST_EQUAL_MSG(Height, y, Printf("Chunk height at <%d, %d>: exp %d, got %d", x, z, y, Height)); + break; + } + } // for y + } // for z + } // for x +} + + + + + +/** Prints out the entire column from the chunk, one block type per line. */ +static void printChunkColumn(const cChunkDesc & a_ChunkDesc, int a_X, int a_Z) +{ + auto prevBlockType = a_ChunkDesc.GetBlockType(a_X, cChunkDef::Height - 1, a_Z); + int count = 1; + LOG("Column {%d, %d}:", a_X, a_Z); + LOG("Yfrom\tYto\tcnt\ttype\ttypeStr"); + for (int y = cChunkDef::Height - 2; y >= 0; --y) + { + auto blockType = a_ChunkDesc.GetBlockType(a_X, y, a_Z); + if (blockType != prevBlockType) + { + LOG("%d\t%d\t%d\t%d\t%s", y + 1, y + count, count, prevBlockType, ItemTypeToString(prevBlockType)); + prevBlockType = blockType; + count = 1; + } + else + { + count += 1; + } + } + LOG("%d\t%d\t%d\t%s", 0, count, prevBlockType, ItemTypeToString(prevBlockType)); +} + + + + + +/** Tests that the default Overworld generator generates a few chunks that have the Overworld look: +- bedrock at their bottom +- a valid overworld block at their height's top +- air at their top, unless the height at that point is equal to full chunk height. +- valid heightmap +Multiple chunks are tested. */ +static void testGenerateOverworld() +{ + LOG("Testing Overworld generator..."); + + // Create a default Overworld generator: + cIniFile ini; + ini.AddValue("General", "Dimension", "Overworld"); + ini.AddValueI("Seed", "Seed", 1); + ini.AddValue("Generator", "Finishers", ""); // Use no finishers, so that we don't have to check too many blocktypes + auto gen = cChunkGenerator::CreateFromIniFile(ini); + TEST_NOTEQUAL(gen, nullptr); + + for (int chunkX = 0; chunkX < 50; ++chunkX) + { + // Generate a chunk: + cChunkDesc chd({chunkX, 0}); + gen->Generate(chunkX, 0, chd); + verifyChunkDescHeightmap(chd); + + // Check that it has bedrock at the bottom: + for (int x = 0; x < cChunkDef::Width; ++x) + { + for (int z = 0; z < cChunkDef::Width; ++z) + { + TEST_EQUAL_MSG(chd.GetBlockType(x, 0, z), E_BLOCK_BEDROCK, Printf("Bedrock floor at {%d, 0, %d}", x, z)); + } + } + + // Check that the blocks on the top are valid Overworld blocks: + static std::set validOverworldBlockTypes = + { + E_BLOCK_STONE, + E_BLOCK_GRASS, + E_BLOCK_WATER, + E_BLOCK_STATIONARY_WATER, + E_BLOCK_LAVA, + E_BLOCK_STATIONARY_LAVA, + E_BLOCK_SAND, + E_BLOCK_GRAVEL, + E_BLOCK_LEAVES, + E_BLOCK_NEW_LEAVES, + }; + for (int x = 0; x < cChunkDef::Width; ++x) + { + for (int z = 0; z < cChunkDef::Width; ++z) + { + auto y = chd.GetHeight(x, z); + auto blockType = chd.GetBlockType(x, y, z); + TEST_EQUAL_MSG(validOverworldBlockTypes.count(blockType), 1, + Printf("Block at {%d, %d, %d}: %d", x, y, z, blockType) + ); + if (y < cChunkDef::Height - 1) + { + TEST_EQUAL_MSG(chd.GetBlockType(x, cChunkDef::Height - 1, z), E_BLOCK_AIR, + Printf("Air at {%d, %d, %d}", x, cChunkDef::Height - 1, z) + ); + } + } + } + } +} + + + + + +/** Tests that the default Nether generator generates a chunk that has the Nether look: +- bedrock at the bottom +- bedrock at the height's top +- netherrack, lava or soulsand anywhere in the middle +- valid heightmap +Multiple chunks are tested. */ +static void testGenerateNether() +{ + LOG("Testing Nether generator..."); + + // Create a default Nether generator: + cIniFile ini; + ini.AddValue("General", "Dimension", "Nether"); + ini.AddValueI("Seed", "Seed", 1); + auto gen = cChunkGenerator::CreateFromIniFile(ini); + TEST_NOTEQUAL(gen, nullptr); + + for (int chunkX = 0; chunkX < 50; ++chunkX) + { + // Generate a chunk: + cChunkDesc chd({chunkX, 0}); + gen->Generate(chunkX, 0, chd); + verifyChunkDescHeightmap(chd); + + // Check that the biome is Nether everywhere: + for (int x = 0; x < cChunkDef::Width; ++x) + { + for (int z = 0; z < cChunkDef::Width; ++z) + { + TEST_EQUAL_MSG(chd.GetBiome(x, z), biNether, Printf("Nether biome at {%d, %d}", x, z)); + } + } + + // Check that it has bedrock at the bottom and height: + int prevHeight = chd.GetHeight(0, 0); + for (int x = 0; x < cChunkDef::Width; ++x) + { + for (int z = 0; z < cChunkDef::Width; ++z) + { + TEST_EQUAL_MSG(chd.GetBlockType(x, 0, z), E_BLOCK_BEDROCK, Printf("Bedrock floor at {%d, 0, %d}", x, z)); + auto y = chd.GetHeight(x, z); + TEST_EQUAL(y, prevHeight); // Same height across the entire chunk + auto blockType = chd.GetBlockType(x, y, z); + TEST_EQUAL_MSG(blockType, E_BLOCK_BEDROCK, + Printf("Bedrock ceiling at {%d, %d, %d}: %d", x, y, z, blockType) + ); + } + } + + // Check that the blocks on the top are valid Overworld blocks: + for (int x = 0; x < cChunkDef::Width; ++x) + { + for (int z = 0; z < cChunkDef::Width; ++z) + { + bool hasSuitableBlockType = false; + for (int y = chd.GetHeight(x, z); y > 0; --y) + { + switch (chd.GetBlockType(x, y, z)) + { + case E_BLOCK_NETHERRACK: + case E_BLOCK_NETHER_QUARTZ_ORE: + case E_BLOCK_LAVA: + case E_BLOCK_STATIONARY_LAVA: + case E_BLOCK_SOULSAND: + { + hasSuitableBlockType = true; + break; + } + } + } // for y + if (!hasSuitableBlockType) + { + printChunkColumn(chd, x, z); + TEST_FAIL(Printf("!hasSuitableBlockType at column {%d, %d} of chunk [%d, 0]", x, z, chunkX)); + } + } + } + } +} + + + + + +IMPLEMENT_TEST_MAIN("BasicGeneratorTest", + testGenerateOverworld(); + testGenerateNether(); +) diff --git a/tests/Generating/CMakeLists.txt b/tests/Generating/CMakeLists.txt index 8c25fd7c3..0232b7a8a 100644 --- a/tests/Generating/CMakeLists.txt +++ b/tests/Generating/CMakeLists.txt @@ -10,10 +10,16 @@ add_definitions(-DTEST_GLOBALS=1) set (SHARED_SRCS ${CMAKE_SOURCE_DIR}/src/BiomeDef.cpp ${CMAKE_SOURCE_DIR}/src/BlockArea.cpp + ${CMAKE_SOURCE_DIR}/src/BlockID.cpp ${CMAKE_SOURCE_DIR}/src/Cuboid.cpp ${CMAKE_SOURCE_DIR}/src/ChunkData.cpp + ${CMAKE_SOURCE_DIR}/src/Enchantments.cpp + ${CMAKE_SOURCE_DIR}/src/FastRandom.cpp + ${CMAKE_SOURCE_DIR}/src/IniFile.cpp + ${CMAKE_SOURCE_DIR}/src/ProbabDistrib.cpp ${CMAKE_SOURCE_DIR}/src/StringCompression.cpp ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp + ${CMAKE_SOURCE_DIR}/src/VoronoiMap.cpp ${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.cpp # Needed for PrefabPiecePool loading @@ -64,11 +70,18 @@ set (GENERATING_SRCS set (SHARED_HDRS ${CMAKE_SOURCE_DIR}/src/BiomeDef.h ${CMAKE_SOURCE_DIR}/src/BlockArea.h + ${CMAKE_SOURCE_DIR}/src/BlockID.h ${CMAKE_SOURCE_DIR}/src/Cuboid.h ${CMAKE_SOURCE_DIR}/src/ChunkData.h + ${CMAKE_SOURCE_DIR}/src/ChunkDef.h + ${CMAKE_SOURCE_DIR}/src/Enchantments.h + ${CMAKE_SOURCE_DIR}/src/FastRandom.h ${CMAKE_SOURCE_DIR}/src/Globals.h + ${CMAKE_SOURCE_DIR}/src/IniFile.h + ${CMAKE_SOURCE_DIR}/src/ProbabDistrib.h ${CMAKE_SOURCE_DIR}/src/StringCompression.h ${CMAKE_SOURCE_DIR}/src/StringUtils.h + ${CMAKE_SOURCE_DIR}/src/VoronoiMap.h ${CMAKE_SOURCE_DIR}/src/Bindings/LuaState.h @@ -151,6 +164,22 @@ source_group("Generating" FILES ${GENERATING_HDRS} ${GENERATING_SRCS}) +# BasicGeneratingTest: +add_executable(BasicGeneratorTest + BasicGeneratorTest.cpp + ${CMAKE_SOURCE_DIR}/src/IniFile.cpp +) +target_link_libraries(BasicGeneratorTest GeneratorTestingSupport) +file(COPY "${CMAKE_SOURCE_DIR}/Server/items.ini" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") +add_test( + NAME BasicGeneratorTest + COMMAND BasicGeneratorTest +) + + + + + # LoadablePieces test: source_group("Data files" FILES Test.cubeset Test1.schematic) add_executable(LoadablePieces @@ -201,6 +230,7 @@ add_test( # Put the projects into solution folders (MSVC): set_target_properties( + BasicGeneratorTest GeneratorTestingSupport LoadablePieces PieceGeneratorBFSTree diff --git a/tests/Generating/Stubs.cpp b/tests/Generating/Stubs.cpp index fb3ed5349..8a8095458 100644 --- a/tests/Generating/Stubs.cpp +++ b/tests/Generating/Stubs.cpp @@ -16,6 +16,12 @@ #include "Blocks/BlockHandler.h" #include "Generating/ChunkDesc.h" #include "DeadlockDetect.h" +#include "Entities/Entity.h" +#include "Mobs/Monster.h" +#include "Simulator/FluidSimulator.h" +#include "Simulator/FireSimulator.h" +#include "MobSpawner.h" +#include "ItemGrid.h" @@ -110,6 +116,7 @@ cBlockInfo::cBlockInfoArray::cBlockInfoArray() + cBoundingBox::cBoundingBox(double, double, double, double, double, double) { } @@ -352,3 +359,68 @@ bool cUUID::FromString(const AString&) + +void cEntity::SetPosition(const Vector3d & a_Position) +{ +} + + + + + +void cEntity::SetHealth(float a_NewHealth) +{ +} + + + + + +cMonster::eFamily cMonster::FamilyFromType(eMonsterType a_Type) +{ + return cMonster::mfAmbient; +} + + + + + +std::unique_ptr cMonster::NewMonsterFromType(eMonsterType a_Type) +{ + return nullptr; +} + + + + + +bool cFluidSimulator::CanWashAway(BLOCKTYPE a_BlockType) +{ + return false; +} + + + + + +bool cFireSimulator::DoesBurnForever(BLOCKTYPE a_BlockType) +{ + return false; +} + + + + + +void cItemGrid::GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed) +{ +} + + + + + +std::set cMobSpawner::GetAllowedMobTypes(EMCSBiome a_Biome) +{ + return {}; +} diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 7a0725f66..b5c905f43 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -172,6 +172,14 @@ public: +/** Fails the test unconditionally, with the specified message. */ +#define TEST_FAIL(MSG) \ + throw TestException(__FILE__, __LINE__, __FUNCTION__, MSG); + + + + + /** Checks that the statement causes an ASSERT trigger. */ #ifdef _DEBUG #define TEST_ASSERTS(Stmt) TEST_THROWS(Stmt, cAssertFailure) @@ -210,7 +218,9 @@ int main() \ } \ catch (const cAssertFailure & exc) \ { \ - LOGERROR("Test has failed, an unexpected ASSERT was triggered at %s:%d", exc.fileName().c_str(), exc.lineNumber()); \ + LOGERROR("Test has failed, an unexpected ASSERT was triggered at %s:%d: %s", \ + exc.fileName().c_str(), exc.lineNumber(), exc.expression().c_str() \ + ); \ return 1; \ } \ catch (...) \ -- cgit v1.2.3