aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParamat <paramat@users.noreply.github.com>2020-11-20 16:11:19 +0000
committerGitHub <noreply@github.com>2020-11-20 16:11:19 +0000
commit872dce5020c5d05597a251c5ce63ebde256f2b64 (patch)
tree57814a188b73f1bf58fdc842b122016953994d5d
parent2f6393f49d5ebf21abfaa7bff876b8c0cf4ca191 (diff)
downloadminetest-872dce5020c5d05597a251c5ce63ebde256f2b64.tar.gz
minetest-872dce5020c5d05597a251c5ce63ebde256f2b64.tar.bz2
minetest-872dce5020c5d05597a251c5ce63ebde256f2b64.zip
Move Mapgen V7 river generation into the main generation loop (#10639)
All terrain generation now occurs in one loop, instead of rivers being carved afterwards in a separate loop. Fixes the removal of nodes added by mods in 'register on generated'. Avoids other problems and reduces the chance of future bugs. Mapchunk generation time is reduced. Also fixes a code mistake which resulted in river channel generation being disabled at floatland altitudes even when floatlands were disabled.
-rw-r--r--src/mapgen/mapgen_v7.cpp79
-rw-r--r--src/mapgen/mapgen_v7.h2
2 files changed, 32 insertions, 49 deletions
diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp
index a1fe25ab6..6b0779e9f 100644
--- a/src/mapgen/mapgen_v7.cpp
+++ b/src/mapgen/mapgen_v7.cpp
@@ -342,10 +342,6 @@ void MapgenV7::makeChunk(BlockMakeData *data)
// Generate base and mountain terrain
s16 stone_surface_max_y = generateTerrain();
- // Generate rivers
- if (spflags & MGV7_RIDGES)
- generateRidgeTerrain();
-
// Create heightmap
updateHeightmap(node_min, node_max);
@@ -467,6 +463,23 @@ bool MapgenV7::getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y)
}
+bool MapgenV7::getRiverChannelFromMap(int idx_xyz, int idx_xz, s16 y)
+{
+ // Maximum width of river channel. Creates the vertical canyon walls
+ float width = 0.2f;
+ float absuwatern = std::fabs(noise_ridge_uwater->result[idx_xz]) * 2.0f;
+ if (absuwatern > width)
+ return false;
+
+ float altitude = y - water_level;
+ float height_mod = (altitude + 17.0f) / 2.5f;
+ float width_mod = width - absuwatern;
+ float nridge = noise_ridge->result[idx_xyz] * std::fmax(altitude, 0.0f) / 7.0f;
+
+ return nridge + width_mod * height_mod >= 0.6f;
+}
+
+
bool MapgenV7::getFloatlandTerrainFromMap(int idx_xyz, float float_offset)
{
return noise_floatland->result[idx_xyz] + floatland_density - float_offset >= 0.0f;
@@ -521,6 +534,15 @@ int MapgenV7::generateTerrain()
}
}
+ // 'Generate rivers in this mapchunk' bool for
+ // simplification of condition checks in y-loop.
+ bool gen_rivers = (spflags & MGV7_RIDGES) && node_max.Y >= water_level - 16 &&
+ !gen_floatlands;
+ if (gen_rivers) {
+ noise_ridge->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
+ noise_ridge_uwater->perlinMap2D(node_min.X, node_min.Z);
+ }
+
//// Place nodes
const v3s16 &em = vm->m_area.getExtent();
s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
@@ -544,10 +566,13 @@ int MapgenV7::generateTerrain()
if (vm->m_data[vi].getContent() != CONTENT_IGNORE)
continue;
- if (y <= surface_y) {
+ bool is_river_channel = gen_rivers &&
+ getRiverChannelFromMap(index3d, index2d, y);
+ if (y <= surface_y && !is_river_channel) {
vm->m_data[vi] = n_stone; // Base terrain
} else if ((spflags & MGV7_MOUNTAINS) &&
- getMountainTerrainFromMap(index3d, index2d, y)) {
+ getMountainTerrainFromMap(index3d, index2d, y) &&
+ !is_river_channel) {
vm->m_data[vi] = n_stone; // Mountain terrain
if (y > stone_surface_max_y)
stone_surface_max_y = y;
@@ -569,45 +594,3 @@ int MapgenV7::generateTerrain()
return stone_surface_max_y;
}
-
-
-void MapgenV7::generateRidgeTerrain()
-{
- if (node_max.Y < water_level - 16 ||
- (node_max.Y >= floatland_ymin && node_min.Y <= floatland_ymax))
- return;
-
- noise_ridge->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
- noise_ridge_uwater->perlinMap2D(node_min.X, node_min.Z);
-
- MapNode n_water(c_water_source);
- MapNode n_air(CONTENT_AIR);
- u32 index3d = 0;
- float width = 0.2f;
-
- for (s16 z = node_min.Z; z <= node_max.Z; z++)
- for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
- u32 vi = vm->m_area.index(node_min.X, y, z);
- for (s16 x = node_min.X; x <= node_max.X; x++, index3d++, vi++) {
- u32 index2d = (z - node_min.Z) * csize.X + (x - node_min.X);
- float uwatern = noise_ridge_uwater->result[index2d] * 2.0f;
- if (std::fabs(uwatern) > width)
- continue;
- // Optimises, but also avoids removing nodes placed by mods in
- // 'on-generated', when generating outside mapchunk.
- content_t c = vm->m_data[vi].getContent();
- if (c != c_stone)
- continue;
-
- float altitude = y - water_level;
- float height_mod = (altitude + 17.0f) / 2.5f;
- float width_mod = width - std::fabs(uwatern);
- float nridge = noise_ridge->result[index3d] *
- std::fmax(altitude, 0.0f) / 7.0f;
- if (nridge + width_mod * height_mod < 0.6f)
- continue;
-
- vm->m_data[vi] = (y > water_level) ? n_air : n_water;
- }
- }
-}
diff --git a/src/mapgen/mapgen_v7.h b/src/mapgen/mapgen_v7.h
index 4020cd935..5db10a304 100644
--- a/src/mapgen/mapgen_v7.h
+++ b/src/mapgen/mapgen_v7.h
@@ -94,10 +94,10 @@ public:
float baseTerrainLevelFromMap(int index);
bool getMountainTerrainAtPoint(s16 x, s16 y, s16 z);
bool getMountainTerrainFromMap(int idx_xyz, int idx_xz, s16 y);
+ bool getRiverChannelFromMap(int idx_xyz, int idx_xz, s16 y);
bool getFloatlandTerrainFromMap(int idx_xyz, float float_offset);
int generateTerrain();
- void generateRidgeTerrain();
private:
s16 mount_zero_level;
> Caller, CallerData> > { }; template<typename Caller, typename Data, typename Key, typename T> class CallerInfo { public: Caller caller; Data data; ResultQueue< Key, T, Caller, Data>* dest; }; template<typename Key, typename T, typename Caller, typename CallerData> class GetRequest { public: GetRequest() { } GetRequest(Key a_key) { key = a_key; } ~GetRequest() { } Key key; std::list<CallerInfo<Caller, CallerData, Key, T> > callers; }; /** * Notes for RequestQueue usage * @param Key unique key to identify a request for a specific resource * @param T ? * @param Caller unique id of calling thread * @param CallerData data passed back to caller */ template<typename Key, typename T, typename Caller, typename CallerData> class RequestQueue { public: bool empty() { return m_queue.empty(); } void add(Key key, Caller caller, CallerData callerdata, ResultQueue<Key, T, Caller, CallerData> *dest) { { JMutexAutoLock lock(m_queue.getMutex()); /* If the caller is already on the list, only update CallerData */ for(typename std::list< GetRequest<Key, T, Caller, CallerData> >::iterator i = m_queue.getList().begin(); i != m_queue.getList().end(); ++i) { GetRequest<Key, T, Caller, CallerData> &request = *i; if(request.key == key) { for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator i = request.callers.begin(); i != request.callers.end(); ++i) { CallerInfo<Caller, CallerData, Key, T> &ca = *i; if(ca.caller == caller) { ca.data = callerdata; return; } } CallerInfo<Caller, CallerData, Key, T> ca; ca.caller = caller; ca.data = callerdata; ca.dest = dest; request.callers.push_back(ca); return; } } } /* Else add a new request to the queue */ GetRequest<Key, T, Caller, CallerData> request; request.key = key; CallerInfo<Caller, CallerData, Key, T> ca; ca.caller = caller; ca.data = callerdata; ca.dest = dest; request.callers.push_back(ca); m_queue.push_back(request); } GetRequest<Key, T, Caller, CallerData> pop(unsigned int timeout_ms) { return m_queue.pop_front(timeout_ms); } GetRequest<Key, T, Caller, CallerData> pop() { return m_queue.pop_frontNoEx(); } void pushResult(GetRequest<Key, T, Caller, CallerData> req, T res) { for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator i = req.callers.begin(); i != req.callers.end(); ++i) { CallerInfo<Caller, CallerData, Key, T> &ca = *i; GetResult<Key,T,Caller,CallerData> result; result.key = req.key; result.item = res; result.caller.first = ca.caller; result.caller.second = ca.data; ca.dest->push_back(result); } } private: MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue; }; #endif