void MapgenV7::generateCaves(s16 max_stone_y) { if (max_stone_y >= node_min.Y) { u32 index = 0; 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 i = vm->m_area.index(node_min.X, y, z); for (s16 x = node_min.X; x <= node_max.X; x++, i++, index++) { float d1 = contour(noise_cave1->result[index]); float d2 = contour(noise_cave2->result[index]); if (d1 * d2 > 0.3) { content_t c = vm->m_data[i].getContent(); if (!ndef->get(c).is_ground_content || c == CONTENT_AIR) continue; vm->m_data[i] = MapNode(CONTENT_AIR); } } } } PseudoRandom ps(blockseed + 21343); u32 bruises_count = (ps.range(1, 4) == 1) ? ps.range(1, 2) : 0; for (u32 i = 0; i < bruises_count; i++) { CaveV7 cave(this, &ps); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenV6::generateCaves(int max_stone_y) { float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed); int volume_nodes = (node_max.X - node_min.X + 1) * (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE; cave_amount = MYMAX(0.0, cave_amount); u32 caves_count = cave_amount * volume_nodes / 50000; u32 bruises_count = 1; PseudoRandom ps(blockseed + 21343); PseudoRandom ps2(blockseed + 1032); if (ps.range(1, 6) == 1) bruises_count = ps.range(0, ps.range(0, 2)); if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) { caves_count /= 3; bruises_count /= 3; } for (u32 i = 0; i < caves_count + bruises_count; i++) { CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source); bool large_cave = (i >= caves_count); cave.makeCave(vm, node_min, node_max, &ps, &ps2, large_cave, max_stone_y, heightmap); } }
void MapgenV6::generateCaves(int max_stone_y) { float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed); int volume_nodes = (node_max.X - node_min.X + 1) * (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE; cave_amount = MYMAX(0.0, cave_amount); u32 caves_count = cave_amount * volume_nodes / 50000; u32 bruises_count = 1; PseudoRandom ps(blockseed + 21343); PseudoRandom ps2(blockseed + 1032); if (ps.range(1, 6) == 1) bruises_count = ps.range(0, ps.range(0, 2)); if (getBiome(node_min) == BT_DESERT) { caves_count /= 3; bruises_count /= 3; } for (u32 i = 0; i < caves_count + bruises_count; i++) { bool large_cave = (i >= caves_count); CaveV6 cave(this, &ps, &ps2, large_cave); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenFractal::generateCaves(s16 max_stone_y) { if (max_stone_y < node_min.Y) return; noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); v3s16 em = vm->m_area.getExtent(); u32 index2d = 0; for (s16 z = node_min.Z; z <= node_max.Z; z++) for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) { bool column_is_open = false; // Is column open to overground u32 vi = vm->m_area.index(x, node_max.Y + 1, z); u32 index3d = (z - node_min.Z) * zstride + (csize.Y + 1) * ystride + (x - node_min.X); // Biome of column Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]); for (s16 y = node_max.Y + 1; y >= node_min.Y - 1; y--, index3d -= ystride, vm->m_area.add_y(em, vi, -1)) { content_t c = vm->m_data[vi].getContent(); if (c == CONTENT_AIR || c == biome->c_water_top || c == biome->c_water) { column_is_open = true; continue; } // Ground float d1 = contour(noise_cave1->result[index3d]); float d2 = contour(noise_cave2->result[index3d]); if (d1 * d2 > 0.3f && ndef->get(c).is_ground_content) { // In tunnel and ground content, excavate vm->m_data[vi] = MapNode(CONTENT_AIR); } else if (column_is_open && (c == biome->c_filler || c == biome->c_stone)) { // Tunnel entrance floor vm->m_data[vi] = MapNode(biome->c_top); column_is_open = false; } else { column_is_open = false; } } } if (node_max.Y > MGFRACTAL_LARGE_CAVE_DEPTH) return; PseudoRandom ps(blockseed + 21343); u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { CaveV5 cave(this, &ps); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenV7::generateCaves(int max_stone_y) { PseudoRandom ps(blockseed + 21343); int volume_nodes = (node_max.X - node_min.X + 1) * (node_max.Y - node_min.Y + 1) * (node_max.Z - node_min.Z + 1); float cave_amount = NoisePerlin2D(&nparams_v7_def_cave, node_min.X, node_min.Y, seed); u32 caves_count = MYMAX(0.0, cave_amount) * volume_nodes / 250000; for (u32 i = 0; i < caves_count; i++) { CaveV7 cave(this, &ps, false); cave.makeCave(node_min, node_max, max_stone_y); } u32 bruises_count = (ps.range(1, 8) == 1) ? ps.range(0, ps.range(0, 2)) : 1; for (u32 i = 0; i < bruises_count; i++) { CaveV7 cave(this, &ps, true); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenV7::generateCaves(int max_stone_y) { PseudoRandom ps(blockseed + 21343); PseudoRandom ps2(blockseed + 1032); int volume_nodes = (node_max.X - node_min.X + 1) * (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE; float cave_amount = NoisePerlin2D(&nparams_v6_def_cave, node_min.X, node_min.Y, seed); u32 caves_count = MYMAX(0.0, cave_amount) * volume_nodes / 50000; for (u32 i = 0; i < caves_count; i++) { CaveV6 cave(this, &ps, &ps2, false, c_water_source, c_lava_source); cave.makeCave(node_min, node_max, max_stone_y); } u32 bruises_count = (ps.range(1, 6) == 1) ? ps.range(0, ps.range(0, 2)) : 1; for (u32 i = 0; i < bruises_count; i++) { CaveV6 cave(this, &ps, &ps2, true, c_water_source, c_lava_source); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenV7P::generateCaves(s16 max_stone_y, s16 large_cave_depth) { if (max_stone_y < node_min.Y) return; PseudoRandom ps(blockseed + 21343); PseudoRandom ps2(blockseed + 1032); u32 large_caves_count = (node_max.Y <= large_cave_depth) ? ps.range(0, 2) : 0; for (u32 i = 0; i < small_caves_count + large_caves_count; i++) { CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source); bool large_cave = (i >= small_caves_count); cave.makeCave(vm, node_min, node_max, &ps, &ps2, large_cave, max_stone_y, heightmap); } }
void MapgenV5::generateCaves(int max_stone_y) { if (max_stone_y < node_min.Y) return; noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); u32 index = 0; 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++, vi++, index++) { // Don't excavate the overgenerated stone at node_max.Y + 1, // this creates a 'roof' over the tunnel, preventing light in // tunnels at mapchunk borders when generating mapchunks upwards. if (y > node_max.Y) continue; float d1 = contour(noise_cave1->result[index]); float d2 = contour(noise_cave2->result[index]); if (d1 * d2 > 0.125f) { content_t c = vm->m_data[vi].getContent(); if (!ndef->get(c).is_ground_content || c == CONTENT_AIR) continue; vm->m_data[vi] = MapNode(CONTENT_AIR); } } } if (node_max.Y > MGV5_LARGE_CAVE_DEPTH) return; PseudoRandom ps(blockseed + 21343); u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { CaveV5 cave(this, &ps); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenV7::generateCaves(int max_stone_y) { if (max_stone_y >= node_min.Y) { u32 index = 0; u32 index2d = 0; 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 i = vm->m_area.index(node_min.X, y, z); for (s16 x = node_min.X; x <= node_max.X; x++, i++, index++, index2d++) { float d1 = contour(noise_cave1->result[index]); float d2 = contour(noise_cave2->result[index]); if (d1 * d2 > 0.3) { Biome *biome = (Biome *)bmgr-> getRaw(biomemap[index2d]); content_t c = vm->m_data[i].getContent(); if (!ndef->get(c).is_ground_content || c == CONTENT_AIR || (y <= water_level && c != biome->c_stone && c != c_stone)) continue; vm->m_data[i] = MapNode(CONTENT_AIR); } } index2d -= ystride; } index2d += ystride; } } PseudoRandom ps(blockseed + 21343); u32 bruises_count = (ps.range(1, 4) == 1) ? ps.range(1, 2) : 0; for (u32 i = 0; i < bruises_count; i++) { CaveV7 cave(this, &ps); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenValleys::generateCaves(s16 max_stone_y) { if (max_stone_y < node_min.Y) return; noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); PseudoRandom ps(blockseed + 72202); MapNode n_air(CONTENT_AIR); MapNode n_lava(c_lava_source); MapNode n_water(c_river_water_source); v3s16 em = vm->m_area.getExtent(); // Cave blend distance near YMIN, YMAX const float massive_cave_blend = 128.f; // noise threshold for massive caves const float massive_cave_threshold = 0.6f; // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume. float yblmin = -map_gen_limit + massive_cave_blend * 1.5f; float yblmax = massive_cave_depth - massive_cave_blend * 1.5f; bool made_a_big_one = false; // Cache the tcave values as they only vary by altitude. if (node_max.Y <= massive_cave_depth) { noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) { float tcave = massive_cave_threshold; if (y < yblmin) { float t = (yblmin - y) / massive_cave_blend; tcave += MYSQUARE(t); } else if (y > yblmax) { float t = (y - yblmax) / massive_cave_blend; tcave += MYSQUARE(t); } tcave_cache[y - node_min.Y + 1] = tcave; } } // lava_depth varies between one and ten as you approach // the bottom of the world. s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit); // This allows random lava spawns to be less common at the surface. s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth; // water_depth varies between ten and one on the way down. s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit); // This allows random water spawns to be more common at the surface. s16 water_chance = MYCUBE(water_features_lim) * water_depth; // Reduce the odds of overflows even further. if (node_max.Y > water_level) { lava_chance /= 5; water_chance /= 5; } u32 index_2d = 0; u32 index_3d = 0; for (s16 z = node_min.Z; z <= node_max.Z; z++) for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) { Biome *biome = (Biome *)bmgr->getRaw(biomemap[index_2d]); bool air_above = false; bool underground = false; u32 index_data = vm->m_area.index(x, node_max.Y + 1, z); index_3d = (z - node_min.Z) * zstride + (csize.Y + 1) * ystride + (x - node_min.X); // Dig caves on down loop to check for air above. for (s16 y = node_max.Y + 1; y >= node_min.Y - 1; y--, index_3d -= ystride, vm->m_area.add_y(em, index_data, -1)) { float terrain = noise_terrain_height->result[index_2d]; // Saves some time. if (y > terrain + 10) { air_above = true; continue; } else if (y < terrain - 40) { underground = true; } // Dig massive caves. if (node_max.Y <= massive_cave_depth && noise_massive_caves->result[index_3d] > tcave_cache[y - node_min.Y + 1]) { vm->m_data[index_data] = n_air; made_a_big_one = true; } content_t c = vm->m_data[index_data].getContent(); float d1 = contour(noise_cave1->result[index_3d]); float d2 = contour(noise_cave2->result[index_3d]); // River water is not set as ground content // in the default game. This can produce strange results // when a cave undercuts a river. However, that's not for // the mapgen to correct. Fix it in lua. if (c == CONTENT_AIR) { air_above = true; } else if (d1 * d2 > 0.3f && ndef->get(c).is_ground_content) { // in a cave vm->m_data[index_data] = n_air; air_above = true; } else if (air_above && (c == biome->c_filler || c == biome->c_stone)) { // at the cave floor s16 sr = ps.range(0,39); u32 j = index_data; vm->m_area.add_y(em, j, 1); if (sr > terrain - y) { // Put dirt in caves near the surface. if (underground) vm->m_data[index_data] = MapNode(biome->c_filler); else vm->m_data[index_data] = MapNode(biome->c_top); } else if (sr < 3 && underground) { sr = abs(ps.next()); if (lava_features_lim > 0 && y <= lava_max_height && c == biome->c_stone && sr < lava_chance) vm->m_data[j] = n_lava; sr -= lava_chance; // If sr < 0 then we should have already placed lava -- // don't immediately dump water on it. if (water_features_lim > 0 && y <= cave_water_max_height && sr >= 0 && sr < water_chance) vm->m_data[j] = n_water; } air_above = false; underground = true; } else if (c == biome->c_filler || c == biome->c_stone) { air_above = false; underground = true; } else { air_above = false; } } } if (node_max.Y <= large_cave_depth && (!made_a_big_one)) { u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { CaveV5 cave(this, &ps); cave.makeCave(node_min, node_max, max_stone_y); } } }
void MapgenV7::generateCaves(s16 max_stone_y) { if (max_stone_y < node_min.Y) return; noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); v3s16 em = vm->m_area.getExtent(); u32 index2d = 0; for (s16 z = node_min.Z; z <= node_max.Z; z++) for (s16 x = node_min.X; x <= node_max.X; x++, index2d++) { bool column_is_open = false; // Is column open to overground bool is_tunnel = false; // Is tunnel or tunnel floor // Indexes at column top (node_max.Y) u32 vi = vm->m_area.index(x, node_max.Y, z); u32 index3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X); // Biome of column Biome *biome = (Biome *)bmgr->getRaw(biomemap[index2d]); // Don't excavate the overgenerated stone at node_max.Y + 1, // this creates a 'roof' over the tunnel, preventing light in // tunnels at mapchunk borders when generating mapchunks upwards. // This 'roof' is removed when the mapchunk above is generated. for (s16 y = node_max.Y; y >= node_min.Y - 1; y--, index3d -= ystride, vm->m_area.add_y(em, vi, -1)) { content_t c = vm->m_data[vi].getContent(); if (c == CONTENT_AIR || c == biome->c_water_top || c == biome->c_water) { column_is_open = true; continue; } // Ground float d1 = contour(noise_cave1->result[index3d]); float d2 = contour(noise_cave2->result[index3d]); if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) { // In tunnel and ground content, excavate vm->m_data[vi] = MapNode(CONTENT_AIR); is_tunnel = true; } else { // Not in tunnel or not ground content if (is_tunnel && column_is_open && (c == biome->c_filler || c == biome->c_stone)) // Tunnel entrance floor vm->m_data[vi] = MapNode(biome->c_top); column_is_open = false; is_tunnel = false; } } } if (node_min.Y >= water_level) return; PseudoRandom ps(blockseed + 21343); u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { CaveV7 cave(this, &ps); cave.makeCave(node_min, node_max, max_stone_y); } }
void MapgenValleys::generateCaves(s16 max_stone_y, s16 large_cave_depth) { if (max_stone_y < node_min.Y) return; noise_cave1->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); noise_cave2->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); PseudoRandom ps(blockseed + 72202); MapNode n_air(CONTENT_AIR); MapNode n_lava(c_lava_source); MapNode n_water(c_river_water_source); v3s16 em = vm->m_area.getExtent(); // Cave blend distance near YMIN, YMAX const float massive_cave_blend = 128.f; // noise threshold for massive caves const float massive_cave_threshold = 0.6f; // mct: 1 = small rare caves, 0.5 1/3rd ground volume, 0 = 1/2 ground volume. float yblmin = -map_gen_limit + massive_cave_blend * 1.5f; float yblmax = massive_cave_depth - massive_cave_blend * 1.5f; bool made_a_big_one = false; // Cache the tcave values as they only vary by altitude. if (node_max.Y <= massive_cave_depth) { noise_massive_caves->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); for (s16 y = node_min.Y - 1; y <= node_max.Y; y++) { float tcave = massive_cave_threshold; if (y < yblmin) { float t = (yblmin - y) / massive_cave_blend; tcave += MYSQUARE(t); } else if (y > yblmax) { float t = (y - yblmax) / massive_cave_blend; tcave += MYSQUARE(t); } tcave_cache[y - node_min.Y + 1] = tcave; } } // lava_depth varies between one and ten as you approach // the bottom of the world. s16 lava_depth = ceil((lava_max_height - node_min.Y + 1) * 10.f / map_gen_limit); // This allows random lava spawns to be less common at the surface. s16 lava_chance = MYCUBE(lava_features_lim) * lava_depth; // water_depth varies between ten and one on the way down. s16 water_depth = ceil((map_gen_limit - abs(node_min.Y) + 1) * 10.f / map_gen_limit); // This allows random water spawns to be more common at the surface. s16 water_chance = MYCUBE(water_features_lim) * water_depth; // Reduce the odds of overflows even further. if (node_max.Y > water_level) { lava_chance /= 3; water_chance /= 3; } u32 index_2d = 0; for (s16 z = node_min.Z; z <= node_max.Z; z++) for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) { Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index_2d]); bool tunnel_air_above = false; bool is_under_river = false; bool underground = false; u32 index_data = vm->m_area.index(x, node_max.Y, z); u32 index_3d = (z - node_min.Z) * zstride_1d + csize.Y * ystride + (x - node_min.X); // Dig caves on down loop to check for air above. // Don't excavate the overgenerated stone at node_max.Y + 1, // this creates a 'roof' over the tunnel, preventing light in // tunnels at mapchunk borders when generating mapchunks upwards. // This 'roof' is removed when the mapchunk above is generated. for (s16 y = node_max.Y; y >= node_min.Y - 1; y--, index_3d -= ystride, vm->m_area.add_y(em, index_data, -1)) { float terrain = noise_terrain_height->result[index_2d]; // Saves some time. if (y > terrain + 10) continue; else if (y < terrain - 40) underground = true; // Dig massive caves. if (node_max.Y <= massive_cave_depth && noise_massive_caves->result[index_3d] > tcave_cache[y - node_min.Y + 1]) { vm->m_data[index_data] = n_air; made_a_big_one = true; continue; } content_t c = vm->m_data[index_data].getContent(); // Detect river water to place riverbed nodes in tunnels if (c == biome->c_river_water) is_under_river = true; float d1 = contour(noise_cave1->result[index_3d]); float d2 = contour(noise_cave2->result[index_3d]); if (d1 * d2 > cave_width && ndef->get(c).is_ground_content) { // in a tunnel vm->m_data[index_data] = n_air; tunnel_air_above = true; } else if (c == biome->c_filler || c == biome->c_stone) { if (tunnel_air_above) { // at the tunnel floor s16 sr = ps.range(0, 39); u32 j = index_data; vm->m_area.add_y(em, j, 1); if (sr > terrain - y) { // Put biome nodes in tunnels near the surface if (is_under_river) vm->m_data[index_data] = MapNode(biome->c_riverbed); else if (underground) vm->m_data[index_data] = MapNode(biome->c_filler); else vm->m_data[index_data] = MapNode(biome->c_top); } else if (sr < 3 && underground) { sr = abs(ps.next()); if (lava_features_lim > 0 && y <= lava_max_height && c == biome->c_stone && sr < lava_chance) vm->m_data[j] = n_lava; sr -= lava_chance; // If sr < 0 then we should have already placed lava -- // don't immediately dump water on it. if (water_features_lim > 0 && y <= cave_water_max_height && sr >= 0 && sr < water_chance) vm->m_data[j] = n_water; } } tunnel_air_above = false; underground = true; } else { tunnel_air_above = false; } } } if (node_max.Y <= large_cave_depth && !made_a_big_one) { u32 bruises_count = ps.range(0, 2); for (u32 i = 0; i < bruises_count; i++) { CavesRandomWalk cave(ndef, &gennotify, seed, water_level, c_water_source, c_lava_source); cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap); } } }