From c413ed298ec22dd7cbc7caf1b1f0c2d03bdf1689 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 27 Jun 2025 10:49:12 +0200 Subject: [PATCH 1/5] unrelated refactor --- src/map.cpp | 8 +++----- src/map_settings_manager.cpp | 15 +++++++++++---- src/map_settings_manager.h | 4 ++++ src/mapgen/mapgen.cpp | 10 ++-------- src/mapgen/mapgen.h | 6 ------ 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index a7e8d2b5fd..03513e4f5a 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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<<" ("< had_blocks; diff --git a/src/map_settings_manager.cpp b/src/map_settings_manager.cpp index 9325bf73d0..2f2221f9b8 100644 --- a/src/map_settings_manager.cpp +++ b/src/map_settings_manager.cpp @@ -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; } diff --git a/src/map_settings_manager.h b/src/map_settings_manager.h index 019e1dafe5..26942359eb 100644 --- a/src/map_settings_manager.h +++ b/src/map_settings_manager.h @@ -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; diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index e8c60c0de0..05d8f314ac 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -1101,14 +1101,8 @@ void MapgenParams::writeParams(Settings *settings) const s32 MapgenParams::getSpawnRangeMax() { - if (!m_mapgen_edges_calculated) { - std::pair 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); + return std::min(-emin, emax); } diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index 17b2431432..22cd40a2c5 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -121,18 +121,12 @@ 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 virtual void setDefaultSettings(Settings *settings) {}; s32 getSpawnRangeMax(); - -private: - bool m_mapgen_edges_calculated = false; }; From 0deeb57d44e7f35f968bf3264efe3046ee9e5747 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 27 Jun 2025 11:26:05 +0200 Subject: [PATCH 2/5] Make mapgen chunk size a v3s16 internally --- src/emerge.cpp | 8 ++---- src/emerge.h | 3 +- src/mapgen/mapgen.cpp | 24 +++++++++------- src/mapgen/mapgen.h | 4 +-- src/script/lua_api/l_mapgen.cpp | 22 ++++++--------- src/servermap.cpp | 4 +-- src/unittest/test_map_settings_manager.cpp | 32 +++++++++++++++++++++- 7 files changed, 62 insertions(+), 35 deletions(-) diff --git a/src/emerge.cpp b/src/emerge.cpp index 8cacdea0c8..6c3310471a 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -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; diff --git a/src/emerge.h b/src/emerge.h index 860d4b6995..982296d50f 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -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 m_mapgens; diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 05d8f314ac..c31d12ac7e 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -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,11 @@ 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); + s16 tmp; + settings->getS16NoEx("chunksize", tmp); + chunksize = v3s16(rangelim(tmp, 1, 24)); delete bparams; bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL); @@ -1091,7 +1092,7 @@ 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->setS16("chunksize", chunksize.X); // TODO settings->setFlagStr("mg_flags", flags, flagdesc_mapgen); if (bparams) @@ -1106,12 +1107,15 @@ s32 MapgenParams::getSpawnRangeMax() } -std::pair get_mapgen_edges(s16 mapgen_limit, s16 chunksize) +std::pair get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize) { + // FIXME: this is no longer exact + const s16 cs = std::max(std::max(chunksize.X, chunksize.Y), chunksize.Z); + // Central chunk offset, in blocks - s16 ccoff_b = -chunksize / 2; + s16 ccoff_b = -cs / 2; // Chunksize, in nodes - s32 csize_n = chunksize * MAP_BLOCKSIZE; + 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; @@ -1127,8 +1131,8 @@ std::pair get_mapgen_edges(s16 mapgen_limit, s16 chunksize) s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1; // 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); // Mapgen edges, in nodes - return std::pair(ccmin - numcmin * csize_n, ccmax + numcmax * csize_n); + return {ccmin - numcmin * csize_n, ccmax + numcmax * csize_n}; } diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index 22cd40a2c5..fd645d9a59 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -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; @@ -322,4 +322,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 get_mapgen_edges(s16 mapgen_limit, s16 chunksize); +std::pair get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 8854fc3c71..126b7afc78 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -849,23 +849,20 @@ 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 params(settingsmgr->makeMapgenParamsCopy()); s16 mapgen_limit; if (lua_isnumber(L, 1)) { - mapgen_limit = lua_tointeger(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 { - std::string chunksize_str; - settingsmgr->getMapSetting("chunksize", &chunksize_str); - chunksize = stoi(chunksize_str, 1, 10); + chunksize = params->chunksize; } std::pair edges = get_mapgen_edges(mapgen_limit, chunksize); @@ -884,12 +881,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 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; } diff --git a/src/servermap.cpp b/src/servermap.cpp index 912c91a9af..2977585dd8 100644 --- a/src/servermap.cpp +++ b/src/servermap.cpp @@ -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; diff --git a/src/unittest/test_map_settings_manager.cpp b/src/unittest/test_map_settings_manager.cpp index 2b844b5e4f..2058d0db45 100644 --- a/src/unittest/test_map_settings_manager.cpp +++ b/src/unittest/test_map_settings_manager.cpp @@ -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 +} From 630ca5daa04deaa2d121f6347a2f28ea567c37c6 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 27 Jun 2025 12:40:55 +0200 Subject: [PATCH 3/5] Allow chunksize to be non-cubic --- doc/lua_api.md | 2 +- doc/world_format.md | 2 +- src/mapgen/mapgen.cpp | 32 ++++++++++++++++++++++++++++---- src/mapgen/mapgen.h | 3 +++ src/script/lua_api/l_mapgen.cpp | 2 ++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 7ce6a543e6..845959d134 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6704,7 +6704,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. diff --git a/doc/world_format.md b/doc/world_format.md index 909613d0b4..2dda2994e9 100644 --- a/doc/world_format.md +++ b/doc/world_format.md @@ -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. diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index c31d12ac7e..625aeab550 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -1073,9 +1073,27 @@ void MapgenParams::readParams(const Settings *settings) settings->getS16NoEx("mapgen_limit", mapgen_limit); settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen); - s16 tmp; - settings->getS16NoEx("chunksize", tmp); - chunksize = v3s16(rangelim(tmp, 1, 24)); + 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); @@ -1092,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.X); // TODO 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); } diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index fd645d9a59..a5afb2a6d3 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -127,6 +127,9 @@ struct MapgenParams { virtual void setDefaultSettings(Settings *settings) {}; s32 getSpawnRangeMax(); + + // Mostly arbitrary limit + constexpr static u32 MAX_CHUNK_VOLUME = 2000; }; diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 126b7afc78..06b07399b1 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -861,6 +861,8 @@ int ModApiMapgen::l_get_mapgen_edges(lua_State *L) v3s16 chunksize; if (lua_isnumber(L, 2)) { chunksize = v3s16(lua_tointeger(L, 2)); + } else if (lua_istable(L, 2)) { + chunksize = check_v3s16(L, 2); } else { chunksize = params->chunksize; } From 2847f3e805fca308787ff62a4601a77bf3621c48 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 22 Aug 2025 19:41:15 +0200 Subject: [PATCH 4/5] Make mapgen edges a vector too --- src/mapgen/mapgen.cpp | 47 +++++++++++++++++++-------------- src/mapgen/mapgen.h | 2 +- src/script/lua_api/l_mapgen.cpp | 6 ++--- src/unittest/test_mapgen.cpp | 17 +++++++++++- 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 625aeab550..d5866460c7 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -1127,25 +1127,13 @@ void MapgenParams::writeParams(Settings *settings) const s32 MapgenParams::getSpawnRangeMax() { auto [emin, emax] = get_mapgen_edges(mapgen_limit, chunksize); - return std::min(-emin, emax); + 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 get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize) +std::pair get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize) { - // FIXME: this is no longer exact - const s16 cs = std::max(std::max(chunksize.X, chunksize.Y), chunksize.Z); - - // 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; // Effective mapgen limit, in blocks // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p) s16 mapgen_limit_b = rangelim(mapgen_limit, @@ -1153,10 +1141,29 @@ std::pair get_mapgen_edges(s16 mapgen_limit, v3s16 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; - // Number of complete chunks from central chunk fullminp/fullmaxp - // to effective mapgen limits. - s16 numcmin = std::max((ccfmin - mapgen_limit_min) / csize_n, 0); - s16 numcmax = std::max((mapgen_limit_max - ccfmax) / csize_n, 0); + + const auto &calculate = [&] (s16 cs) -> std::pair { + // 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 = 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 {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}; } diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index a5afb2a6d3..f360ba8d12 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -325,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 get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize); +std::pair get_mapgen_edges(s16 mapgen_limit, v3s16 chunksize); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 06b07399b1..63198845b1 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -867,9 +867,9 @@ int ModApiMapgen::l_get_mapgen_edges(lua_State *L) chunksize = params->chunksize; } - std::pair 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; } diff --git a/src/unittest/test_mapgen.cpp b/src/unittest/test_mapgen.cpp index dc69420e83..e7fd131667 100644 --- a/src/unittest/test_mapgen.cpp +++ b/src/unittest/test_mapgen.cpp @@ -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)); +} From 0cb84dfe708dc12e29f41a20089c9610326f16b7 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 22 Aug 2025 19:53:13 +0200 Subject: [PATCH 5/5] feature --- builtin/game/features.lua | 1 + doc/lua_api.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/builtin/game/features.lua b/builtin/game/features.lua index db70e9a667..747b3aee73 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -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) diff --git a/doc/lua_api.md b/doc/lua_api.md index 845959d134..8061d9dd3c 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -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, } ```