1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-30 19:22:14 +00:00
This commit is contained in:
sfan5 2025-09-29 08:32:55 -03:00 committed by GitHub
commit 67349b5cfb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 151 additions and 73 deletions

View file

@ -51,6 +51,7 @@ core.features = {
on_timer_four_args = true,
particlespawner_exclude_player = true,
generate_decorations_biomes = true,
chunksize_vector = true,
}
function core.has_feature(arg)

View file

@ -5849,6 +5849,8 @@ Utilities
particlespawner_exclude_player = true,
-- core.generate_decorations() supports `use_mapgen_biomes` parameter (5.14.0)
generate_decorations_biomes = true,
-- 'chunksize' mapgen setting can be a vector, instead of a single number (5.15.0)
chunksize_vector = true,
}
```
@ -6704,7 +6706,7 @@ Environment access
in that order.
* `mapgen_limit` is an optional number. If it is absent, its value is that
of the *active* mapgen setting `"mapgen_limit"`.
* `chunksize` is an optional number. If it is absent, its value is that
* `chunksize` is an optional number or vector. If it is absent, its value is that
of the *active* mapgen setting `"chunksize"`.
* `core.get_mapgen_chunksize()`
* Returns the currently active chunksize of the mapgen, as a vector.

View file

@ -249,7 +249,7 @@ Example content:
# Map File Format
Luanti maps consist of `MapBlock`s, chunks of 16x16x16 nodes.
Luanti maps consist of `MapBlock`s, each holds 16x16x16 nodes.
In addition to the bulk node data, `MapBlock`s stored on disk also contain
other things.

View file

@ -190,7 +190,7 @@ void EmergeManager::initMapgens(MapgenParams *params)
mgparams = params;
v3s16 csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
v3s16 csize = params->chunksize * MAP_BLOCKSIZE;
biomegen = biomemgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
for (u32 i = 0; i != m_threads.size(); i++) {
@ -319,11 +319,9 @@ bool EmergeManager::isBlockInQueue(v3s16 pos)
//
// TODO(hmmmm): Move this to ServerMap
v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, s16 chunksize)
v3s16 EmergeManager::getContainingChunk(v3s16 blockpos, v3s16 chunksize)
{
s16 coff = -chunksize / 2;
v3s16 chunk_offset(coff, coff, coff);
v3s16 chunk_offset = -chunksize / 2;
return getContainerPos(blockpos - chunk_offset, chunksize)
* chunksize + chunk_offset;

View file

@ -189,7 +189,8 @@ public:
int getSpawnLevelAtPoint(v2s16 p);
bool isBlockUnderground(v3s16 blockpos);
static v3s16 getContainingChunk(v3s16 blockpos, s16 chunksize);
/// @return min edge of chunk in block units
static v3s16 getContainingChunk(v3s16 blockpos, v3s16 chunksize);
private:
std::vector<Mapgen *> m_mapgens;

View file

@ -775,12 +775,10 @@ void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
u32 size_MB = block_area_nodes.getVolume() * sizeof(MapNode) / 1000000U;
if(size_MB >= 1)
{
infostream<<"initialEmerge: area: ";
if (size_MB >= 4) {
infostream << "initialEmerge: area: ";
block_area_nodes.print(infostream);
infostream<<" ("<<size_MB<<"MB)";
infostream<<std::endl;
infostream << " (" << size_MB << "MB)" << std::endl;
}
std::map<v3s16, bool> had_blocks;

View file

@ -125,10 +125,20 @@ MapgenParams *MapSettingsManager::makeMapgenParams()
if (mapgen_params)
return mapgen_params;
MapgenParams *params = makeMapgenParamsCopy();
if (!params)
return nullptr;
mapgen_params = params;
return params;
}
MapgenParams *MapSettingsManager::makeMapgenParamsCopy() const
{
// Note: can't return mapgen_params here, because we want a copy.
assert(m_map_settings);
assert(m_defaults);
// Now, get the mapgen type so we can create the appropriate MapgenParams
std::string mg_name;
MapgenType mgtype = getMapSetting("mg_name", &mg_name) ?
Mapgen::getMapgenType(mg_name) : MAPGEN_DEFAULT;
@ -151,8 +161,5 @@ MapgenParams *MapSettingsManager::makeMapgenParams()
params->MapgenParams::readParams(m_map_settings.get());
params->readParams(m_map_settings.get());
// Hold onto our params
mapgen_params = params;
return params;
}

View file

@ -52,7 +52,11 @@ public:
bool loadMapMeta();
bool saveMapMeta();
/// @brief Finalizes and creates the mapgen params
MapgenParams *makeMapgenParams();
/// @brief Creates a copy of the mapgen params without making the manager immutable
MapgenParams *makeMapgenParamsCopy() const;
private:
std::string m_map_meta_path;

View file

@ -100,7 +100,7 @@ Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeParams *emerge) :
water_level = params->water_level;
mapgen_limit = params->mapgen_limit;
flags = params->flags;
csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
csize = params->chunksize * MAP_BLOCKSIZE;
/*
We are losing half our entropy by doing this, but it is necessary to
@ -1071,10 +1071,29 @@ void MapgenParams::readParams(const Settings *settings)
settings->getS16NoEx("water_level", water_level);
settings->getS16NoEx("mapgen_limit", mapgen_limit);
settings->getS16NoEx("chunksize", chunksize);
settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
chunksize = rangelim(chunksize, 1, 10);
std::string chunksize_str;
settings->getNoEx("chunksize", chunksize_str);
if (is_number(chunksize_str)) {
chunksize = v3s16(stoi(chunksize_str, 1, 999));
} else if (auto tmp = str_to_v3f(chunksize_str); tmp.has_value()) {
chunksize = v3s16(
rangelim(tmp->X, 1, 999),
rangelim(tmp->Y, 1, 999),
rangelim(tmp->Z, 1, 999)
);
} else if (!chunksize_str.empty()) {
errorstream << "MapgenParams: invalid chunksize \"" << chunksize_str
<< "\"" << std::endl;
}
// Finally check the volume limit
if (u32 v = chunksize.X * chunksize.Y * chunksize.Z; v > MAX_CHUNK_VOLUME) {
errorstream << "MapgenParams: chunksize " << chunksize
<< " is too big (volume > " << MAX_CHUNK_VOLUME
<< "), falling back to the default." << std::endl;
chunksize = v3s16(5);
}
delete bparams;
bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
@ -1091,9 +1110,15 @@ void MapgenParams::writeParams(Settings *settings) const
settings->setU64("seed", seed);
settings->setS16("water_level", water_level);
settings->setS16("mapgen_limit", mapgen_limit);
settings->setS16("chunksize", chunksize);
settings->setFlagStr("mg_flags", flags, flagdesc_mapgen);
// Write as number if cubic, for backwards-compatibility
if (chunksize.X == chunksize.Y && chunksize.Y == chunksize.Z) {
settings->setS16("chunksize", chunksize.X);
} else {
settings->setV3F("chunksize", v3f::from(chunksize));
}
if (bparams)
bparams->writeParams(settings);
}
@ -1101,29 +1126,14 @@ void MapgenParams::writeParams(Settings *settings) const
s32 MapgenParams::getSpawnRangeMax()
{
if (!m_mapgen_edges_calculated) {
std::pair<s16, s16> edges = get_mapgen_edges(mapgen_limit, chunksize);
mapgen_edge_min = edges.first;
mapgen_edge_max = edges.second;
m_mapgen_edges_calculated = true;
}
return MYMIN(-mapgen_edge_min, mapgen_edge_max);
auto [emin, emax] = get_mapgen_edges(mapgen_limit, chunksize);
s32 min_xz = std::max(emin.X, emin.Z), max_xz = std::min(emax.X, emax.Z);
return std::min(-min_xz, max_xz);
}
std::pair<s16, s16> get_mapgen_edges(s16 mapgen_limit, s16 chunksize)
std::pair<v3s16, v3s16> get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize)
{
// Central chunk offset, in blocks
s16 ccoff_b = -chunksize / 2;
// Chunksize, in nodes
s32 csize_n = chunksize * MAP_BLOCKSIZE;
// Minp/maxp of central chunk, in nodes
s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
s16 ccmax = ccmin + csize_n - 1;
// Fullminp/fullmaxp of central chunk, in nodes
s16 ccfmin = ccmin - MAP_BLOCKSIZE;
s16 ccfmax = ccmax + MAP_BLOCKSIZE;
// Effective mapgen limit, in blocks
// Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
s16 mapgen_limit_b = rangelim(mapgen_limit,
@ -1131,10 +1141,29 @@ std::pair<s16, s16> get_mapgen_edges(s16 mapgen_limit, s16 chunksize)
// Effective mapgen limits, in nodes
s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
const auto &calculate = [&] (s16 cs) -> std::pair<s16, s16> {
// Central chunk offset, in blocks
s16 ccoff_b = -cs / 2;
// Chunksize, in nodes
s32 csize_n = cs * MAP_BLOCKSIZE;
// Minp/maxp of central chunk, in nodes
s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
s16 ccmax = ccmin + csize_n - 1;
// Fullminp/fullmaxp of central chunk, in nodes
s16 ccfmin = ccmin - MAP_BLOCKSIZE;
s16 ccfmax = ccmax + MAP_BLOCKSIZE;
// Number of complete chunks from central chunk fullminp/fullmaxp
// to effective mapgen limits.
s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
s16 numcmin = std::max((ccfmin - mapgen_limit_min) / csize_n, 0);
s16 numcmax = std::max((mapgen_limit_max - ccfmax) / csize_n, 0);
return {ccmin - numcmin * csize_n, ccmax + numcmax * csize_n};
};
// Mapgen edges, in nodes
return std::pair<s16, s16>(ccmin - numcmin * csize_n, ccmax + numcmax * csize_n);
v3s16 emin, emax;
std::tie(emin.X, emax.X) = calculate(chunksize.X);
std::tie(emin.Y, emax.Y) = calculate(chunksize.Y);
std::tie(emin.Z, emax.Z) = calculate(chunksize.Z);
return {emin, emax};
}

View file

@ -111,7 +111,7 @@ struct MapgenParams {
virtual ~MapgenParams();
MapgenType mgtype = MAPGEN_DEFAULT;
s16 chunksize = 5;
v3s16 chunksize = v3s16(5);
u64 seed = 0;
s16 water_level = 1;
s16 mapgen_limit = MAX_MAP_GENERATION_LIMIT;
@ -121,9 +121,6 @@ struct MapgenParams {
BiomeParams *bparams = nullptr;
s16 mapgen_edge_min = -MAX_MAP_GENERATION_LIMIT;
s16 mapgen_edge_max = MAX_MAP_GENERATION_LIMIT;
virtual void readParams(const Settings *settings);
virtual void writeParams(Settings *settings) const;
// Default settings for g_settings such as flags
@ -131,8 +128,8 @@ struct MapgenParams {
s32 getSpawnRangeMax();
private:
bool m_mapgen_edges_calculated = false;
// Mostly arbitrary limit
constexpr static u32 MAX_CHUNK_VOLUME = 2000;
};
@ -328,4 +325,4 @@ protected:
// Calculate exact edges of the outermost mapchunks that are within the set
// mapgen_limit. Returns the minimum and maximum edges in nodes in that order.
std::pair<s16, s16> get_mapgen_edges(s16 mapgen_limit, s16 chunksize);
std::pair<v3s16, v3s16> get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize);

View file

@ -849,28 +849,27 @@ int ModApiMapgen::l_get_mapgen_edges(lua_State *L)
// MapSettingsManager::makeMapgenParams cannot be used here because it would
// make mapgen settings immutable from then on. Mapgen settings should stay
// mutable until after mod loading ends.
std::unique_ptr<MapgenParams> params(settingsmgr->makeMapgenParamsCopy());
s16 mapgen_limit;
if (lua_isnumber(L, 1)) {
mapgen_limit = lua_tointeger(L, 1);
} else {
std::string mapgen_limit_str;
settingsmgr->getMapSetting("mapgen_limit", &mapgen_limit_str);
mapgen_limit = stoi(mapgen_limit_str, 0, MAX_MAP_GENERATION_LIMIT);
mapgen_limit = params->mapgen_limit;
}
s16 chunksize;
v3s16 chunksize;
if (lua_isnumber(L, 2)) {
chunksize = lua_tointeger(L, 2);
chunksize = v3s16(lua_tointeger(L, 2));
} else if (lua_istable(L, 2)) {
chunksize = check_v3s16(L, 2);
} else {
std::string chunksize_str;
settingsmgr->getMapSetting("chunksize", &chunksize_str);
chunksize = stoi(chunksize_str, 1, 10);
chunksize = params->chunksize;
}
std::pair<s16, s16> edges = get_mapgen_edges(mapgen_limit, chunksize);
push_v3s16(L, v3s16(1, 1, 1) * edges.first);
push_v3s16(L, v3s16(1, 1, 1) * edges.second);
auto edges = get_mapgen_edges(mapgen_limit, chunksize);
push_v3s16(L, edges.first);
push_v3s16(L, edges.second);
return 2;
}
@ -884,12 +883,9 @@ int ModApiMapgen::l_get_mapgen_chunksize(lua_State *L)
// MapSettingsManager::makeMapgenParams cannot be used here because it would
// make mapgen settings immutable from then on. Mapgen settings should stay
// mutable until after mod loading ends.
std::unique_ptr<MapgenParams> params(settingsmgr->makeMapgenParamsCopy());
std::string chunksize_str;
settingsmgr->getMapSetting("chunksize", &chunksize_str);
s16 chunksize = stoi(chunksize_str, 1, 10);
push_v3s16(L, {chunksize, chunksize, chunksize});
push_v3s16(L, params->chunksize);
return 1;
}

View file

@ -200,9 +200,9 @@ bool ServerMap::blockpos_over_mapgen_limit(v3s16 p)
bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
{
assert(data);
s16 csize = getMapgenParams()->chunksize;
const v3s16 csize = getMapgenParams()->chunksize;
const v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
const v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
const v3s16 bpmax = bpmin + csize - v3s16(1);
if (!m_chunks_in_progress.insert(bpmin).second)
return false;

View file

@ -7,7 +7,9 @@
#include "noise.h"
#include "settings.h"
#include "mapgen/mapgen_v5.h"
#include "emerge.h"
#include "util/hashing.h"
#include "irrlicht_changes/printing.h"
#include "map_settings_manager.h"
class TestMapSettingsManager : public TestBase {
@ -23,6 +25,7 @@ public:
void testMapSettingsManager();
void testMapMetaSaveLoad();
void testMapMetaFailures();
void testChunks();
};
static TestMapSettingsManager g_test_instance;
@ -32,6 +35,7 @@ void TestMapSettingsManager::runTests(IGameDef *gamedef)
TEST(testMapSettingsManager);
TEST(testMapMetaSaveLoad);
TEST(testMapMetaFailures);
TEST(testChunks);
}
////////////////////////////////////////////////////////////////////////////////
@ -141,7 +145,7 @@ void TestMapSettingsManager::testMapSettingsManager()
// Now make our Params and see if the values are correctly sourced
MapgenParams *params = mgr.makeMapgenParams();
UASSERT(params->mgtype == MAPGEN_V5);
UASSERT(params->chunksize == 5);
UASSERT(params->chunksize == v3s16(5));
UASSERT(params->water_level == 15);
UASSERT(params->seed == 1234);
UASSERT((params->flags & MG_LIGHT) == 0);
@ -246,3 +250,29 @@ void TestMapSettingsManager::testMapMetaFailures()
UASSERT(!mgr2.loadMapMeta());
}
}
void TestMapSettingsManager::testChunks()
{
v3s16 csize(5);
#define GET(x) EmergeManager::getContainingChunk(x, csize)
// origin chunk goes from (-2, -2, -2) -> (3, 3, 3) excl
UASSERTEQ(auto, GET(v3s16(-2, -2, -2)), v3s16(-2, -2, -2));
UASSERTEQ(auto, GET(v3s16(0, 0, 0)), v3s16(-2, -2, -2));
UASSERTEQ(auto, GET(v3s16(1, 1, 1)), v3s16(-2, -2, -2));
UASSERTEQ(auto, GET(v3s16(2, 2, 2)), v3s16(-2, -2, -2));
UASSERTEQ(auto, GET(v3s16(2, 3, 2)), v3s16(-2, 3, -2));
UASSERTEQ(auto, GET(v3s16(0, -3, 0)), v3s16(-2, -7, -2));
csize = v3s16(5, 2, 5);
UASSERTEQ(auto, GET(v3s16(0, 0, 0)), v3s16(-2, -1, -2));
UASSERTEQ(auto, GET(v3s16(0, 1, 0)), v3s16(-2, 1, -2));
UASSERTEQ(auto, GET(v3s16(3, 3, 3)), v3s16(3, 3, 3));
csize = v3s16(1);
UASSERTEQ(auto, GET(v3s16(1, 2, 3)), v3s16(1, 2, 3));
UASSERTEQ(auto, GET(v3s16(-3, -2, -1)), v3s16(-3, -2, -1));
#undef GET
}

View file

@ -7,6 +7,7 @@
#include "emerge.h"
#include "mapgen/mapgen.h"
#include "mapgen/mg_biome.h"
#include "irrlicht_changes/printing.h"
#include "mock_server.h"
class TestMapgen : public TestBase
@ -18,6 +19,7 @@ public:
void runTests(IGameDef *gamedef);
void testBiomeGen(IGameDef *gamedef);
void testMapgenEdges();
};
static TestMapgen g_test_instance;
@ -37,6 +39,7 @@ namespace {
void TestMapgen::runTests(IGameDef *gamedef)
{
TEST(testBiomeGen, gamedef);
TEST(testMapgenEdges);
}
void TestMapgen::testBiomeGen(IGameDef *gamedef)
@ -98,7 +101,7 @@ void TestMapgen::testBiomeGen(IGameDef *gamedef)
{ 0, "deciduous_forest_shore", S16_MIN },
{ -100, "deciduous_forest_shore", S16_MIN },
};
for (const auto expected : expected_biomes) {
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
@ -123,3 +126,15 @@ void TestMapgen::testBiomeGen(IGameDef *gamedef)
}
}
void TestMapgen::testMapgenEdges()
{
v3s16 emin, emax;
std::tie(emin, emax) = get_mapgen_edges(31007, v3s16(5));
UASSERTEQ(auto, emin, v3s16(-30912));
UASSERTEQ(auto, emax, v3s16(30927));
std::tie(emin, emax) = get_mapgen_edges(502 * MAP_BLOCKSIZE, v3s16(1, 2, 1));
UASSERTEQ(auto, emin, v3s16(-8016));
UASSERTEQ(auto, emax, v3s16(8031, 8015, 8031));
}