int MapgenV5::getSpawnLevelAtPoint(v2s16 p) { float f = 0.55 + NoisePerlin2D(&noise_factor->np, p.X, p.Y, seed); if (f < 0.01) f = 0.01; else if (f >= 1.0) f *= 1.6; float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed); // noise_height 'offset' is the average level of terrain. At least 50% of // terrain will be below this. // Raising the maximum spawn level above 'water_level + 16' is necessary // for when noise_height 'offset' is set much higher than water_level. s16 max_spawn_y = MYMAX(noise_height->np.offset, water_level + 16); // Starting spawn search at max_spawn_y + 128 ensures 128 nodes of open // space above spawn position. Avoids spawning in possibly sealed voids. for (s16 y = max_spawn_y + 128; y >= water_level; y--) { float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed); if (n_ground * f > y - h) { // If solid if (y < water_level || y > max_spawn_y) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point // y + 2 because y is surface and due to biome 'dust' nodes. return y + 2; } } // Unsuitable spawn position, no ground found return MAX_MAP_GENERATION_LIMIT; }
// For BiomeGen type 'BiomeGenOriginal' float BiomeManager::getHeatAtPosOriginal(v3s16 pos, NoiseParams &np_heat, NoiseParams &np_heat_blend, u64 seed) { return NoisePerlin2D(&np_heat, pos.X, pos.Z, seed) + NoisePerlin2D(&np_heat_blend, pos.X, pos.Z, seed); }
// For BiomeGen type 'BiomeGenOriginal' float BiomeManager::getHumidityAtPosOriginal(v3s16 pos, NoiseParams &np_humidity, NoiseParams &np_humidity_blend, u64 seed) { return NoisePerlin2D(&np_humidity, pos.X, pos.Z, seed) + NoisePerlin2D(&np_humidity_blend, pos.X, pos.Z, seed); }
int MapgenV5::getSpawnLevelAtPoint(v2s16 p) { //TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO); float f = 0.55 + NoisePerlin2D(&noise_factor->np, p.X, p.Y, seed); if (f < 0.01) f = 0.01; else if (f >= 1.0) f *= 1.6; float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed); for (s16 y = 128; y >= -128; y--) { float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed); if (n_ground * f > y - h) { // If solid // If either top 2 nodes of search are solid this is inside a // mountain or floatland with possibly no space for the player to spawn. if (y >= 127) { return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point } else { // Ground below at least 2 nodes of empty space if (y <= water_level || y > water_level + 16) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point else return y; } } } //printf("getGroundLevelAtPoint: %dus\n", t.stop()); return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn position, no ground found }
float MapgenV7P::mountainLevelAtPoint(s16 x, s16 z) { float mnt_h_n = NoisePerlin2D(&noise_mount_height->np, x, z, seed); float mnt_n = NoisePerlin2D(&noise_mountain->np, x, z, seed); return mnt_n * mnt_h_n; }
int MapgenV5::getGroundLevelAtPoint(v2s16 p) { //TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO); float f = 0.55 + NoisePerlin2D(&noise_factor->np, p.X, p.Y, seed); if (f < 0.01) f = 0.01; else if (f >= 1.0) f *= 1.6; float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed); s16 search_start = 128; // Only bother searching this range, actual s16 search_end = -128; // ground level is rarely higher or lower. for (s16 y = search_start; y >= search_end; y--) { float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed); // If solid if (n_ground * f > y - h) { // If either top 2 nodes of search are solid this is inside a // mountain or floatland with no space for the player to spawn. if (y >= search_start - 1) return MAX_MAP_GENERATION_LIMIT; else return y; // Ground below at least 2 nodes of space } } //printf("getGroundLevelAtPoint: %dus\n", t.stop()); return -MAX_MAP_GENERATION_LIMIT; }
int MapgenV5::getGroundLevelAtPoint(v2s16 p) { //TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO); float f = 0.55 + NoisePerlin2D(&noise_factor->np, p.X, p.Y, seed); if (f < 0.01) f = 0.01; else if (f >= 1.0) f *= 1.6; float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed); s16 search_top = water_level + 15; s16 search_base = water_level; s16 level = -31000; for (s16 y = search_top; y >= search_base; y--) { float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed); if (n_ground * f > y - h) { if (y >= search_top - 7) break; else level = y; break; } } //printf("getGroundLevelAtPoint: %dus\n", t.stop()); return level; }
Biome *MapgenV7::getBiomeAtPoint(v3s16 p) { float heat = NoisePerlin2D(&noise_heat->np, p.X, p.Z, seed); float humidity = NoisePerlin2D(&noise_humidity->np, p.X, p.Z, seed); s16 groundlevel = baseTerrainLevelAtPoint(p.X, p.Z); return bmgr->getBiome(heat, humidity, groundlevel); }
Biome *BiomeGenOriginal::calcBiomeAtPoint(v3s16 pos) const { float heat = NoisePerlin2D(&m_params->np_heat, pos.X, pos.Z, m_params->seed) + NoisePerlin2D(&m_params->np_heat_blend, pos.X, pos.Z, m_params->seed); float humidity = NoisePerlin2D(&m_params->np_humidity, pos.X, pos.Z, m_params->seed) + NoisePerlin2D(&m_params->np_humidity_blend, pos.X, pos.Z, m_params->seed); return calcBiomeFromNoise(heat, humidity, pos.Y); }
float MapgenValleys::terrainLevelAtPoint(s16 x, s16 z) { TerrainNoise tn; float rivers = NoisePerlin2D(&noise_rivers->np, x, z, seed); float valley = NoisePerlin2D(&noise_valley_depth->np, x, z, seed); float inter_valley_slope = NoisePerlin2D(&noise_inter_valley_slope->np, x, z, seed); tn.x = x; tn.z = z; tn.terrain_height = NoisePerlin2D(&noise_terrain_height->np, x, z, seed); tn.rivers = &rivers; tn.valley = &valley; tn.valley_profile = NoisePerlin2D(&noise_valley_profile->np, x, z, seed); tn.slope = &inter_valley_slope; tn.inter_valley_fill = 0.f; tn.cliffs = 0.f; tn.corr = 0.f; if (fast_terrain) { tn.inter_valley_fill = NoisePerlin2D(&noise_inter_valley_fill->np, x, z, seed); if (cliff_terrain) tn.cliffs = NoisePerlin2D(&noise_cliffs->np, x, z, seed); if (rugged_terrain) tn.corr = NoisePerlin2D(&noise_corr->np, x, z, seed); } return adjustedTerrainLevelFromNoise(&tn); }
float MapgenV7::baseTerrainLevelAtPoint(int x, int z) { float terrain_mod = NoisePerlin2DNoTxfm(noise_terrain_mod->np, x, z, seed); float hselect = NoisePerlin2D(noise_height_select->np, x, z, seed); float persist = abs(NoisePerlin2DNoTxfm(noise_terrain_persist->np, x, z, seed)); noise_terrain_base->np->persist = persist; float terrain_base = NoisePerlin2D(noise_terrain_base->np, x, z, seed); float height_base = terrain_base * terrain_mod; noise_terrain_alt->np->persist = persist; float height_alt = NoisePerlin2D(noise_terrain_alt->np, x, z, seed); return (height_base * hselect) + (height_alt * (1.0 - hselect)); }
s16 BiomeDefManager::calcBlockHeat(v3s16 p, u64 seed, float timeofday, float totaltime) { //variant 1: full random //f32 heat = NoisePerlin3D(np_heat, p.X, env->getGameTime()/100, p.Z, seed); //variant 2: season change based on default heat map const f32 offset = 20; // = np_heat->offset const f32 scale = 20; // = np_heat->scale const f32 range = 20; f32 heat = NoisePerlin2D(np_heat, p.X, p.Z, seed); // 0..50..100 heat -= np_heat->offset; // -50..0..+50 // normalizing - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50, if (np_heat->scale) heat /= np_heat->scale / scale; // -20..0..+20 f32 seasonv = totaltime; seasonv /= 86400 * g_settings->getS16("year_days"); // season change speed seasonv += (f32)p.X / 3000; // you can walk to area with other season seasonv = sin(seasonv * M_PI); heat += (range * (heat < 0 ? 2 : 0.5)) * seasonv; // -60..0..30 heat += offset; // -40..0..50 heat += p.Y / -333; // upper=colder, lower=hotter, 3c per 1000 // daily change, hotter at sun +4, colder at night -4 heat += 8 * (sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-44..20..54 return heat; }
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); } }
int MapgenV7::getSpawnLevelAtPoint(v2s16 p) { // Base terrain calculation s16 y = baseTerrainLevelAtPoint(p.X, p.Y); // Ridge/river terrain calculation float width = 0.2; float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2; // if inside a river this is an unsuitable spawn point if (fabs(uwatern) <= width) return MAX_MAP_GENERATION_LIMIT; // Mountain terrain calculation int iters = 128; while (iters--) { if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) { // Air, y is ground level if (y <= water_level || y > water_level + 16) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point else return y; } y++; } // Unsuitable spawn point, no ground surface found return MAX_MAP_GENERATION_LIMIT; }
bool MapgenV7::getMountainTerrainAtPoint(int x, int y, int z) { float mnt_h_n = NoisePerlin2D(&noise_mount_height->np, x, z, seed); float height_modifier = -((float)y / rangelim(mnt_h_n, 80.0, 150.0)); float mnt_n = NoisePerlin3D(&noise_mountain->np, x, y, z, seed); return mnt_n + height_modifier >= 0.6; }
s16 BiomeManager::calcBlockHeat(v3POS p, uint64_t seed, float timeofday, float totaltime, bool use_weather) { //variant 1: full random //f32 heat = NoisePerlin3D(np_heat, p.X, env->getGameTime()/100, p.Z, seed); //variant 2: season change based on default heat map auto heat = NoisePerlin2D(&(mapgen_params->np_biome_heat), p.X, p.Z, seed); // -30..20..70 if (use_weather) { f32 seasonv = totaltime; seasonv /= 86400 * year_days; // season change speed seasonv += (f32)p.X / weather_heat_width; // you can walk to area with other season seasonv = sin(seasonv * M_PI); //heat += (weather_heat_season * (heat < offset ? 2 : 0.5)) * seasonv; // -60..0..30 heat += (weather_heat_season) * seasonv; // -60..0..30 // daily change, hotter at sun +4, colder at night -4 heat += weather_heat_daily * (sin(cycle_shift(timeofday, -0.25) * M_PI) - 0.5); //-64..0..34 } heat += p.Y / weather_heat_height; // upper=colder, lower=hotter, 3c per 1000 if (weather_hot_core && p.Y < -(MAX_MAP_GENERATION_LIMIT-weather_hot_core)) heat += 6000 * (1.0-((float)(p.Y - -MAX_MAP_GENERATION_LIMIT)/weather_hot_core)); //hot core, later via realms return heat; }
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); } }
int MapgenV7::getGroundLevelAtPoint(v2s16 p) { // Base terrain calculation s16 y = baseTerrainLevelAtPoint(p.X, p.Y); // Ridge/river terrain calculation float width = 0.2; float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2; // actually computing the depth of the ridge is much more expensive; // if inside a river, simply guess if (fabs(uwatern) <= width) return water_level - 10; // Mountain terrain calculation int iters = 128; // don't even bother iterating more than 128 times.. while (iters--) { //current point would have been air if (!getMountainTerrainAtPoint(p.X, y, p.Y)) return y; y++; } return y; }
bool MapgenV7::getMountainTerrainAtPoint(s16 x, s16 y, s16 z) { float mnt_h_n = NoisePerlin2D(&noise_mount_height->np, x, z, seed); float density_gradient = -((float)y / mnt_h_n); float mnt_n = NoisePerlin3D(&noise_mountain->np, x, y, z, seed); return mnt_n + density_gradient >= 0.0; }
//needs to be updated float MapgenV7::baseTerrainLevelAtPoint(s16 x, s16 z) { float hselect = NoisePerlin2D(&noise_height_select->np, x, z, seed); hselect = rangelim(hselect, 0.0, 1.0); float persist = NoisePerlin2D(&noise_terrain_persist->np, x, z, seed); noise_terrain_base->np.persist = persist; float height_base = NoisePerlin2D(&noise_terrain_base->np, x, z, seed); noise_terrain_alt->np.persist = persist; float height_alt = NoisePerlin2D(&noise_terrain_alt->np, x, z, seed); if (height_alt > height_base) return height_alt; return (height_base * hselect) + (height_alt * (1.0 - hselect)); }
int LuaPerlinNoise::l_get2d(lua_State *L) { NO_MAP_LOCK_REQUIRED; LuaPerlinNoise *o = checkobject(L, 1); v2f p = check_v2f(L, 2); lua_Number val = NoisePerlin2D(&o->np, p.X, p.Y, 0); lua_pushnumber(L, val); return 1; }
bool MapgenV6::getHaveAppleTree(v2s16 p) { /*is_apple_tree = noise2d_perlin( 0.5+(float)p.X/100, 0.5+(float)p.Z/100, data->seed+342902, 3, 0.45) > 0.2;*/ float noise = NoisePerlin2D(np_apple_trees, p.X, p.Y, seed); return noise > 0.2; }
int MapgenV7::getGroundLevelAtPoint(v2s16 p) { s16 groundlevel = baseTerrainLevelAtPoint(p.X, p.Y); float heat = NoisePerlin2D(bmgr->np_heat, p.X, p.Y, seed); float humidity = NoisePerlin2D(bmgr->np_humidity, p.X, p.Y, seed); Biome *b = bmgr->getBiome(heat, humidity, groundlevel); s16 y = groundlevel; if (y > water_level) { int iters = 1024; // don't even bother iterating more than 1024 times.. while (iters--) { float ridgenoise = NoisePerlin3D(noise_ridge->np, p.X, y, p.Y, seed); if (ridgenoise * (float)(y * y) < 15.0) break; y--; } } return y + b->top_depth; }
void TestNoise::testNoise2dPoint() { NoiseParams np_normal(20, 40, v3f(50, 50, 50), 9, 5, 0.6, 2.0); u32 i = 0; for (u32 y = 0; y != 10; y++) for (u32 x = 0; x != 10; x++, i++) { float actual = NoisePerlin2D(&np_normal, x, y, 1337); float expected = expected_2d_results[i]; UASSERT(fabs(actual - expected) <= 0.00001); } }
int MapgenFlat::getGroundLevelAtPoint(v2s16 p) { float n_terrain = NoisePerlin2D(&noise_terrain->np, p.X, p.Y, seed); if ((spflags & MGFLAT_LAKES) && n_terrain < lake_threshold) { s16 depress = (lake_threshold - n_terrain) * lake_steepness; return ground_level - depress; } else if ((spflags & MGFLAT_HILLS) && n_terrain > hill_threshold) { s16 rise = (n_terrain - hill_threshold) * hill_steepness; return ground_level + rise; } else { return ground_level; } }
float MapgenV6::getTreeAmount(v2s16 p) { /*double noise = noise2d_perlin( 0.5+(float)p.X/125, 0.5+(float)p.Y/125, seed+2, 4, 0.66);*/ float noise = NoisePerlin2D(np_trees, p.X, p.Y, seed); float zeroval = -0.39; if (noise < zeroval) return 0; else return 0.04 * (noise - zeroval) / (1.0 - zeroval); }
int MapgenValleys::getSpawnLevelAtPoint(v2s16 p) { // Check to make sure this isn't a request for a location in a river. float rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed); if (fabs(rivers) < river_size_factor) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point s16 level_at_point = terrainLevelAtPoint(p.X, p.Y); if (level_at_point <= water_level || level_at_point > water_level + 32) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point else return level_at_point; }
s16 BiomeDefManager::calcBlockHumidity(v3s16 p, u64 seed, float timeofday, float totaltime) { f32 humidity = NoisePerlin2D(np_humidity, p.X, p.Z, seed); f32 seasonv = totaltime; seasonv /= 86400 * 2; // bad weather change speed (2 days) seasonv += (f32)p.Z / 300; humidity += 30 * sin(seasonv * M_PI); humidity += -12 * (sin(cycle_shift(timeofday, -0.1) * M_PI) - 0.5); humidity = rangelim(humidity, 0, 100); return humidity; }
float MapgenV6::getHumidity(v2s16 p) { /*double noise = noise2d_perlin( 0.5+(float)p.X/500, 0.5+(float)p.Y/500, seed+72384, 4, 0.66); noise = (noise + 1.0)/2.0;*/ float noise = NoisePerlin2D(np_humidity, p.X, p.Y, seed); if (noise < 0.0) noise = 0.0; if (noise > 1.0) noise = 1.0; return noise; }
int MapgenV7::getSpawnLevelAtPoint(v2s16 p) { // If rivers are enabled, first check if in a river if (spflags & MGV7_RIDGES) { float width = 0.2; float uwatern = NoisePerlin2D(&noise_ridge_uwater->np, p.X, p.Y, seed) * 2; if (fabs(uwatern) <= width) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point } // Terrain noise 'offset' is the average level of that terrain. // At least 50% of terrain will be below the higher of base and alt terrain // 'offset's. // Raising the maximum spawn level above 'water_level + 16' is necessary // for when terrain 'offset's are set much higher than water_level. s16 max_spawn_y = MYMAX(MYMAX(noise_terrain_alt->np.offset, noise_terrain_base->np.offset), water_level + 16); // Base terrain calculation s16 y = baseTerrainLevelAtPoint(p.X, p.Y); // If mountains are disabled, terrain level is base terrain level. // Avoids mid-air spawn where mountain terrain would have been. if (!(spflags & MGV7_MOUNTAINS)) { if (y < water_level || y > max_spawn_y) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point // y + 2 because y is surface level and due to biome 'dust' return y + 2; } // Search upwards for first node without mountain terrain int iters = 256; while (iters > 0 && y <= max_spawn_y) { if (!getMountainTerrainAtPoint(p.X, y + 1, p.Y)) { if (y <= water_level || y > max_spawn_y) return MAX_MAP_GENERATION_LIMIT; // Unsuitable spawn point // y + 1 due to biome 'dust' return y + 1; } y++; iters--; } // Unsuitable spawn point return MAX_MAP_GENERATION_LIMIT; }