From 50928b97593ba6381ec776e0408aad92761c0840 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Thu, 28 Nov 2024 19:16:07 +0100 Subject: [PATCH] Mapgen: Add rudimentary unittests --- src/mapgen/mg_biome.cpp | 28 ++------ src/mapgen/mg_biome.h | 52 ++++++++------- src/script/lua_api/l_mapgen.cpp | 25 +++---- src/unittest/CMakeLists.txt | 1 + src/unittest/test_mapgen.cpp | 114 ++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 58 deletions(-) create mode 100644 src/unittest/test_mapgen.cpp diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index a1c4f5810..788bacede 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -25,21 +25,7 @@ BiomeManager::BiomeManager(Server *server) : // Create default biome to be used in case none exist Biome *b = new Biome; - b->name = "default"; - b->flags = 0; - b->depth_top = 0; - b->depth_filler = -MAX_MAP_GENERATION_LIMIT; - b->depth_water_top = 0; - b->depth_riverbed = 0; - b->min_pos = v3s16(-MAX_MAP_GENERATION_LIMIT, - -MAX_MAP_GENERATION_LIMIT, -MAX_MAP_GENERATION_LIMIT); - b->max_pos = v3s16(MAX_MAP_GENERATION_LIMIT, - MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT); - b->heat_point = 0.0; - b->humidity_point = 0.0; - b->vertical_blend = 0; - b->weight = 1.0f; b->m_nodenames.emplace_back("mapgen_stone"); b->m_nodenames.emplace_back("mapgen_stone"); @@ -64,11 +50,13 @@ void BiomeManager::clear() { EmergeManager *emerge = m_server->getEmergeManager(); - // Remove all dangling references in Decorations - DecorationManager *decomgr = emerge->getWritableDecorationManager(); - for (size_t i = 0; i != decomgr->getNumObjects(); i++) { - Decoration *deco = (Decoration *)decomgr->getRaw(i); - deco->biomes.clear(); + if (emerge) { + // Remove all dangling references in Decorations + DecorationManager *decomgr = emerge->getWritableDecorationManager(); + for (size_t i = 0; i != decomgr->getNumObjects(); i++) { + Decoration *deco = (Decoration *)decomgr->getRaw(i); + deco->biomes.clear(); + } } // Don't delete the first biome @@ -299,8 +287,6 @@ ObjDef *Biome::clone() const ObjDef::cloneTo(obj); NodeResolver::cloneTo(obj); - obj->flags = flags; - obj->c_top = c_top; obj->c_filler = c_filler; obj->c_stone = c_stone; diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 3e9de89d9..637ec14b1 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -19,6 +19,12 @@ class BiomeManager; typedef u16 biome_t; +constexpr v3s16 MAX_MAP_GENERATION_LIMIT_V3( + MAX_MAP_GENERATION_LIMIT, + MAX_MAP_GENERATION_LIMIT, + MAX_MAP_GENERATION_LIMIT +); + #define BIOME_NONE ((biome_t)0) enum BiomeType { @@ -29,32 +35,32 @@ class Biome : public ObjDef, public NodeResolver { public: ObjDef *clone() const; - u32 flags; - - content_t c_top; - content_t c_filler; - content_t c_stone; - content_t c_water_top; - content_t c_water; - content_t c_river_water; - content_t c_riverbed; - content_t c_dust; + content_t + c_top = CONTENT_IGNORE, + c_filler = CONTENT_IGNORE, + c_stone = CONTENT_IGNORE, + c_water_top = CONTENT_IGNORE, + c_water = CONTENT_IGNORE, + c_river_water = CONTENT_IGNORE, + c_riverbed = CONTENT_IGNORE, + c_dust = CONTENT_IGNORE; std::vector c_cave_liquid; - content_t c_dungeon; - content_t c_dungeon_alt; - content_t c_dungeon_stair; + content_t + c_dungeon = CONTENT_IGNORE, + c_dungeon_alt = CONTENT_IGNORE, + c_dungeon_stair = CONTENT_IGNORE; - s16 depth_top; - s16 depth_filler; - s16 depth_water_top; - s16 depth_riverbed; + s16 depth_top = 0; + s16 depth_filler = -MAX_MAP_GENERATION_LIMIT; + s16 depth_water_top = 0; + s16 depth_riverbed = 0; - v3s16 min_pos; - v3s16 max_pos; - float heat_point; - float humidity_point; - s16 vertical_blend; - float weight; + v3s16 min_pos = -MAX_MAP_GENERATION_LIMIT_V3; + v3s16 max_pos = MAX_MAP_GENERATION_LIMIT_V3; + float heat_point = 0.0f; + float humidity_point = 0.0f; + s16 vertical_blend = 0; + float weight = 1.0f; virtual void resolveNodeNames(); }; diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index d102b357f..a7101ee92 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -366,22 +366,19 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef) ModApiMapgen::es_BiomeTerrainType, BIOMETYPE_NORMAL); Biome *b = BiomeManager::create(biometype); - b->name = getstringfield_default(L, index, "name", ""); - b->depth_top = getintfield_default(L, index, "depth_top", 0); - b->depth_filler = getintfield_default(L, index, "depth_filler", -31000); - b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0); - b->depth_riverbed = getintfield_default(L, index, "depth_riverbed", 0); - b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f); - b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f); - b->vertical_blend = getintfield_default(L, index, "vertical_blend", 0); - b->weight = getfloatfield_default(L, index, "weight", 1.f); - b->flags = 0; // reserved + getstringfield(L, index, "name", b->name); + getintfield(L, index, "depth_top", b->depth_top); + getintfield(L, index, "depth_filler", b->depth_filler); + getintfield(L, index, "depth_water_top", b->depth_water_top); + getintfield(L, index, "depth_riverbed", b->depth_riverbed); + getfloatfield(L, index, "heat_point", b->heat_point); + getfloatfield(L, index, "humidity_point", b->humidity_point); + getintfield(L, index, "vertical_blend", b->vertical_blend); + getfloatfield(L, index, "weight", b->weight); - b->min_pos = getv3s16field_default( - L, index, "min_pos", v3s16(-31000, -31000, -31000)); + b->min_pos = getv3s16field_default(L, index, "min_pos", b->min_pos); getintfield(L, index, "y_min", b->min_pos.Y); - b->max_pos = getv3s16field_default( - L, index, "max_pos", v3s16(31000, 31000, 31000)); + b->max_pos = getv3s16field_default(L, index, "max_pos", b->max_pos); getintfield(L, index, "y_max", b->max_pos.Y); std::vector &nn = b->m_nodenames; diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt index 46e4f9a18..2b70a6918 100644 --- a/src/unittest/CMakeLists.txt +++ b/src/unittest/CMakeLists.txt @@ -17,6 +17,7 @@ set (UNITTEST_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_lua.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_map.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mapblock.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_mapgen.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_modchannels.cpp diff --git a/src/unittest/test_mapgen.cpp b/src/unittest/test_mapgen.cpp new file mode 100644 index 000000000..f72e85ba3 --- /dev/null +++ b/src/unittest/test_mapgen.cpp @@ -0,0 +1,114 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 Minetest core developers & community + +#include "test.h" + +#include "emerge.h" +#include "mapgen/mapgen.h" +#include "mapgen/mg_biome.h" +#include "mock_server.h" + +class TestMapgen : public TestBase +{ +public: + TestMapgen() { TestManager::registerTestModule(this); } + const char *getName() { return "TestMapgen"; } + + void runTests(IGameDef *gamedef); + + void testBiomeGen(IGameDef *gamedef); +}; + +static TestMapgen g_test_instance; + +namespace { + class MockBiomeManager : public BiomeManager { + public: + MockBiomeManager(Server *server) : BiomeManager(server) {} + + void setNodeDefManager(const NodeDefManager *ndef) + { + m_ndef = ndef; + } + }; +} + +void TestMapgen::runTests(IGameDef *gamedef) +{ + TEST(testBiomeGen, gamedef); +} + +void TestMapgen::testBiomeGen(IGameDef *gamedef) +{ + MockServer server(getTestTempDirectory()); + MockBiomeManager bmgr(&server); + bmgr.setNodeDefManager(gamedef->getNodeDefManager()); + + { + // Add some biomes (equivalent to l_register_biome) + // Taken from minetest_game/mods/default/mapgen.lua + size_t bmgr_count = bmgr.getNumObjects(); // this is 1 ? + + Biome *b = BiomeManager::create(BIOMETYPE_NORMAL); + b->name = "deciduous_forest"; + b->c_top = t_CONTENT_GRASS; + b->depth_top = 1; + b->c_filler = t_CONTENT_BRICK; // dirt + b->depth_filler = 3; + b->c_stone = t_CONTENT_STONE; + b->min_pos.Y = 1; + b->heat_point = 60.0f; + b->humidity_point = 68.0f; + UASSERT(bmgr.add(b) != OBJDEF_INVALID_HANDLE); + + b = BiomeManager::create(BIOMETYPE_NORMAL); + b->name = "deciduous_forest_shore"; + b->c_top = t_CONTENT_BRICK; // dirt + b->depth_top = 1; + b->c_filler = t_CONTENT_BRICK; // dirt + b->depth_filler = 3; + b->c_stone = t_CONTENT_STONE; + b->max_pos.Y = 0; + b->heat_point = 60.0f; + b->humidity_point = 68.0f; + UASSERT(bmgr.add(b) != OBJDEF_INVALID_HANDLE); + UASSERT(bmgr.getNumObjects() - bmgr_count == 2); + } + + + std::unique_ptr params(BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL)); + + constexpr v3s16 CSIZE(16, 16, 16); // misleading name. measured in nodes. + std::unique_ptr biomegen( + bmgr.createBiomeGen(BIOMEGEN_ORIGINAL, params.get(), CSIZE) + ); + + { + // Test biome transitions + // getBiomeAtIndex (Y only) + // getNextTransitionY + const struct { + s16 check_y; + const char *name; + s16 next_y; + } expected_biomes[] = { + { MAX_MAP_GENERATION_LIMIT, "deciduous_forest", 1 }, + // ^ FIXME: next_y should be 0 (min_pos.Y - 1) + { 1, "deciduous_forest", 0 }, + { 0, "deciduous_forest_shore", -MAX_MAP_GENERATION_LIMIT }, + { -100, "deciduous_forest_shore", -MAX_MAP_GENERATION_LIMIT }, + }; + for (const auto expected : expected_biomes) { + Biome *biome = biomegen->getBiomeAtIndex( + (1 * CSIZE.X) + 1, // index in CSIZE 2D noise map + v3s16(2000, expected.check_y, -1000) // absolute coordinates + ); + s16 next_y = biomegen->getNextTransitionY(expected.check_y); + + UASSERTEQ(auto, biome->name, expected.name); + UASSERTEQ(auto, next_y, expected.next_y); + } + } +} +