Generate biomes: Recalculate biome at biome lower limit
authorparamat <paramat@users.noreply.github.com>
Sat, 16 Sep 2017 01:46:26 +0000 (02:46 +0100)
committerparamat <mat.gregory@virginmedia.com>
Sat, 16 Sep 2017 04:14:04 +0000 (05:14 +0100)
Prevents biome nodes passing below the defined y_min of that biome.

doc/lua_api.txt
src/mapgen.cpp

index de3927a74331f3a40cd23a1adb204845bf32dedd..231456bbb583a1c83c47230814c377b0ff91bda9 100644 (file)
@@ -4630,9 +4630,6 @@ Definition tables
 
 ### Biome definition (`register_biome`)
 
-**Note**
-The Biome API is still in an experimental phase and subject to change.
-
     {
         name = "tundra",
         node_dust = "default:snow",
@@ -4659,13 +4656,6 @@ The Biome API is still in an experimental phase and subject to change.
         y_max = 31000,
     --  ^ Lower and upper limits for biome.
     --  ^ Limits are relative to y = water_level - 1.
-    --  ^ Because biome is not recalculated for every node in a node column
-    --  ^ some biome materials can exceed their limits, especially stone.
-    --  ^ For each node column in a mapchunk, biome is only recalculated at column
-    --  ^ top and at each of these surfaces:
-    --  ^ Ground below air, water below air, ground below water.
-    --  ^ The selected biome then stays in effect for all nodes below until
-    --  ^ column base or the next biome recalculation.
         heat_point = 0,
         humidity_point = 50,
     --  ^ Characteristic average temperature and humidity for the biome.
index fe7f74cfab318cd6589bd6610745e5820205666d..1d72ec037dcaeb43b7b0631973b7f2bb4247b30e 100644 (file)
@@ -633,6 +633,7 @@ void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
                u16 base_filler = 0;
                u16 depth_water_top = 0;
                u16 depth_riverbed = 0;
+               s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT;
                u32 vi = vm->m_area.index(x, node_max.Y, z);
 
                // Check node at base of mapchunk above, either a node of a previously
@@ -650,22 +651,20 @@ void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
 
                for (s16 y = node_max.Y; y >= node_min.Y; y--) {
                        content_t c = vm->m_data[vi].getContent();
-
-                       // Biome is recalculated each time an upper surface is detected while
-                       // working down a column. The selected biome then remains in effect for
-                       // all nodes below until the next surface and biome recalculation.
-                       // Biome is recalculated:
+                       // Biome is (re)calculated:
                        // 1. At the surface of stone below air or water.
                        // 2. At the surface of water below air.
                        // 3. When stone or water is detected but biome has not yet been calculated.
+                       // 4. When stone or water is detected just below a biome's lower limit.
                        bool is_stone_surface = (c == c_stone) &&
-                               (air_above || water_above || !biome);
+                               (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4
 
                        bool is_water_surface =
                                (c == c_water_source || c == c_river_water_source) &&
-                               (air_above || !biome);
+                               (air_above || !biome || y < biome_y_min); // 2, 3, 4
 
                        if (is_stone_surface || is_water_surface) {
+                               // (Re)calculate biome
                                // Limit to +-MAX MAP GENERATION LIMIT to work with biome y_min / y_max.
                                s32 relative_y = rangelim(y - biome_zero_level,
                                        -MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
@@ -677,9 +676,11 @@ void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
                                depth_top = biome->depth_top;
                                base_filler = MYMAX(depth_top +
                                        biome->depth_filler +
-                                       noise_filler_depth->result[index], 0.f);
+                                       noise_filler_depth->result[index], 0.0f);
                                depth_water_top = biome->depth_water_top;
                                depth_riverbed = biome->depth_riverbed;
+                               biome_y_min = rangelim(biome->y_min + biome_zero_level,
+                                       -MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
 
                                // Detect stone type for dungeons during every biome calculation.
                                // If none detected the last selected biome stone is chosen.