Mapgen: Add rudimentary unittests

This commit is contained in:
SmallJoker 2024-11-28 19:16:07 +01:00 committed by SmallJoker
parent c7fe2ee5c9
commit 50928b9759
5 changed files with 162 additions and 58 deletions

@ -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;

@ -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<content_t> 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();
};

@ -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<std::string> &nn = b->m_nodenames;

@ -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

@ -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<BiomeParams> params(BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL));
constexpr v3s16 CSIZE(16, 16, 16); // misleading name. measured in nodes.
std::unique_ptr<BiomeGen> 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);
}
}
}