X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmapgen.cpp;h=3f83d21785757042960442886586453e4ca42f32;hb=63867b1a372a4d1a4a4ffdec9d0862b094211a89;hp=0646a8826a0804279218d6dee92f7fb17332aa2e;hpb=7c0e707cf1d0031788567bfec66f6c13ec901cdc;p=minetest.git diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 0646a8826..3f83d2178 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -20,194 +20,177 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mapgen.h" #include "voxel.h" #include "noise.h" -#include "biome.h" +#include "gamedef.h" +#include "mg_biome.h" #include "mapblock.h" #include "mapnode.h" #include "map.h" -//#include "serverobject.h" #include "content_sao.h" #include "nodedef.h" +#include "emerge.h" #include "content_mapnode.h" // For content_mapnode_get_new_name #include "voxelalgorithms.h" #include "profiler.h" #include "settings.h" // For g_settings #include "main.h" // For g_profiler #include "treegen.h" -#include "mapgen_v6.h" -#include "mapgen_v7.h" +#include "serialization.h" +#include "util/serialize.h" +#include "filesys.h" +#include "log.h" + +const char *GenElementManager::ELEMENT_TITLE = "element"; FlagDesc flagdesc_mapgen[] = { - {"trees", MG_TREES}, - {"caves", MG_CAVES}, - {"dungeons", MG_DUNGEONS}, - {"v6_jungles", MGV6_JUNGLES}, - {"v6_biome_blend", MGV6_BIOME_BLEND}, - {"flat", MG_FLAT}, - {NULL, 0} + {"trees", MG_TREES}, + {"caves", MG_CAVES}, + {"dungeons", MG_DUNGEONS}, + {"flat", MG_FLAT}, + {"light", MG_LIGHT}, + {NULL, 0} }; -FlagDesc flagdesc_ore[] = { - {"absheight", OREFLAG_ABSHEIGHT}, - {"scatter_noisedensity", OREFLAG_DENSITY}, - {"claylike_nodeisnt", OREFLAG_NODEISNT}, - {NULL, 0} +FlagDesc flagdesc_gennotify[] = { + {"dungeon", 1 << GENNOTIFY_DUNGEON}, + {"temple", 1 << GENNOTIFY_TEMPLE}, + {"cave_begin", 1 << GENNOTIFY_CAVE_BEGIN}, + {"cave_end", 1 << GENNOTIFY_CAVE_END}, + {"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN}, + {"large_cave_end", 1 << GENNOTIFY_LARGECAVE_END}, + {"decoration", 1 << GENNOTIFY_DECORATION}, + {NULL, 0} }; /////////////////////////////////////////////////////////////////////////////// +Mapgen::Mapgen() +{ + generating = false; + id = -1; + seed = 0; + water_level = 0; + flags = 0; + + vm = NULL; + ndef = NULL; + heightmap = NULL; + biomemap = NULL; +} + -Ore *createOre(OreType type) { - switch (type) { - case ORE_SCATTER: - return new OreScatter; - case ORE_SHEET: - return new OreSheet; - //case ORE_CLAYLIKE: //TODO: implement this! - // return new OreClaylike; - default: - return NULL; - } +Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) : + gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids) +{ + generating = false; + id = mapgenid; + seed = (int)params->seed; + water_level = params->water_level; + flags = params->flags; + csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE); + + vm = NULL; + ndef = NULL; + heightmap = NULL; + biomemap = NULL; } -void Ore::resolveNodeNames(INodeDefManager *ndef) { - if (ore == CONTENT_IGNORE) { - ore = ndef->getId(ore_name); - if (ore == CONTENT_IGNORE) { - errorstream << "Ore::resolveNodeNames: ore node '" - << ore_name << "' not defined"; - ore = CONTENT_AIR; - wherein = CONTENT_AIR; - } - } - - if (wherein == CONTENT_IGNORE) { - wherein = ndef->getId(wherein_name); - if (wherein == CONTENT_IGNORE) { - errorstream << "Ore::resolveNodeNames: wherein node '" - << wherein_name << "' not defined"; - ore = CONTENT_AIR; - wherein = CONTENT_AIR; - } - } +Mapgen::~Mapgen() +{ } -void Ore::placeOre(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax) { - int in_range = 0; +u32 Mapgen::getBlockSeed(v3s16 p, int seed) +{ + return (u32)seed + + p.Z * 38134234 + + p.Y * 42123 + + p.X * 23; +} - in_range |= (nmin.Y <= height_max && nmax.Y >= height_min); - if (flags & OREFLAG_ABSHEIGHT) - in_range |= (nmin.Y >= -height_max && nmax.Y <= -height_min) << 1; - if (!in_range) - return; - resolveNodeNames(mg->ndef); - - int ymin, ymax; - - if (in_range & ORE_RANGE_MIRROR) { - ymin = MYMAX(nmin.Y, -height_max); - ymax = MYMIN(nmax.Y, -height_min); - } else { - ymin = MYMAX(nmin.Y, height_min); - ymax = MYMIN(nmax.Y, height_max); - } - if (clust_size >= ymax - ymin + 1) - return; - - nmin.Y = ymin; - nmax.Y = ymax; - generate(mg->vm, mg->seed, blockseed, nmin, nmax); +u32 Mapgen::getBlockSeed2(v3s16 p, int seed) +{ + return noise3d(p.X, p.Y, p.Z, seed); } -void OreScatter::generate(ManualMapVoxelManipulator *vm, int seed, - u32 blockseed, v3s16 nmin, v3s16 nmax) { - PseudoRandom pr(blockseed); - MapNode n_ore(ore, 0, ore_param2); - - int volume = (nmax.X - nmin.X + 1) * - (nmax.Y - nmin.Y + 1) * - (nmax.Z - nmin.Z + 1); - int csize = clust_size; - int orechance = (csize * csize * csize) / clust_num_ores; - int nclusters = volume / clust_scarcity; - - for (int i = 0; i != nclusters; i++) { - int x0 = pr.range(nmin.X, nmax.X - csize + 1); - int y0 = pr.range(nmin.Y, nmax.Y - csize + 1); - int z0 = pr.range(nmin.Z, nmax.Z - csize + 1); - - if (np && (NoisePerlin3D(np, x0, y0, z0, seed) < nthresh)) - continue; - - for (int z1 = 0; z1 != csize; z1++) - for (int y1 = 0; y1 != csize; y1++) - for (int x1 = 0; x1 != csize; x1++) { - if (pr.range(1, orechance) != 1) - continue; - - u32 i = vm->m_area.index(x0 + x1, y0 + y1, z0 + z1); - if (vm->m_data[i].getContent() == wherein) - vm->m_data[i] = n_ore; - } +// Returns Y one under area minimum if not found +s16 Mapgen::findGroundLevelFull(v2s16 p2d) +{ + v3s16 em = vm->m_area.getExtent(); + s16 y_nodes_max = vm->m_area.MaxEdge.Y; + s16 y_nodes_min = vm->m_area.MinEdge.Y; + u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y); + s16 y; + + for (y = y_nodes_max; y >= y_nodes_min; y--) { + MapNode &n = vm->m_data[i]; + if (ndef->get(n).walkable) + break; + + vm->m_area.add_y(em, i, -1); } + return (y >= y_nodes_min) ? y : y_nodes_min - 1; } -void OreSheet::generate(ManualMapVoxelManipulator *vm, int seed, - u32 blockseed, v3s16 nmin, v3s16 nmax) { - PseudoRandom pr(blockseed + 4234); - MapNode n_ore(ore, 0, ore_param2); - - int max_height = clust_size; - int y_start = pr.range(nmin.Y, nmax.Y - max_height); - - if (!noise) { - int sx = nmax.X - nmin.X + 1; - int sz = nmax.Z - nmin.Z + 1; - noise = new Noise(np, 0, sx, sz); +s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) +{ + v3s16 em = vm->m_area.getExtent(); + u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y); + s16 y; + + for (y = ymax; y >= ymin; y--) { + MapNode &n = vm->m_data[i]; + if (ndef->get(n).walkable) + break; + + vm->m_area.add_y(em, i, -1); } - noise->seed = seed + y_start; - noise->perlinMap2D(nmin.X, nmin.Z); - + return y; +} + + +void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) +{ + if (!heightmap) + return; + + //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO); int index = 0; - for (int z = nmin.Z; z <= nmax.Z; z++) - for (int x = nmin.X; x <= nmax.X; x++) { - float noiseval = noise->result[index++]; - if (noiseval < nthresh) - continue; - - int height = max_height * (1. / pr.range(1, 3)); - int y0 = y_start + np->scale * noiseval; //pr.range(1, 3) - 1; - int y1 = y0 + height; - for (int y = y0; y != y1; y++) { - u32 i = vm->m_area.index(x, y, z); - if (!vm->m_area.contains(i)) + for (s16 z = nmin.Z; z <= nmax.Z; z++) { + for (s16 x = nmin.X; x <= nmax.X; x++, index++) { + s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y); + + // if the values found are out of range, trust the old heightmap + if (y == nmax.Y && heightmap[index] > nmax.Y) continue; - - if (vm->m_data[i].getContent() == wherein) - vm->m_data[i] = n_ore; + if (y == nmin.Y - 1 && heightmap[index] < nmin.Y) + continue; + + heightmap[index] = y; } } + //printf("updateHeightmap: %dus\n", t.stop()); } -void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nmax) { +void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nmax) +{ bool isliquid, wasliquid; v3s16 em = vm->m_area.getExtent(); for (s16 z = nmin.Z; z <= nmax.Z; z++) { for (s16 x = nmin.X; x <= nmax.X; x++) { wasliquid = true; - + u32 i = vm->m_area.index(x, nmax.Y, z); for (s16 y = nmax.Y; y >= nmin.Y; y--) { isliquid = ndef->get(vm->m_data[i]).isLiquid(); - - // there was a change between liquid and nonliquid, add to queue + + // there was a change between liquid and nonliquid, add to queue. if (isliquid != wasliquid) trans_liquid->push_back(v3s16(x, y, z)); @@ -219,7 +202,8 @@ void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nm } -void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) { +void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax) +{ ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG); VoxelArea a(nmin, nmax); @@ -233,10 +217,11 @@ void Mapgen::setLighting(v3s16 nmin, v3s16 nmax, u8 light) { } -void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { +void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) +{ if (light <= 1 || !a.contains(p)) return; - + u32 vi = vm->m_area.index(p); MapNode &nn = vm->m_data[vi]; @@ -244,9 +229,9 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { // should probably compare masked, but doesn't seem to make a difference if (light <= nn.param1 || !ndef->get(nn).light_propagates) return; - + nn.param1 = light; - + lightSpread(a, p + v3s16(0, 0, 1), light); lightSpread(a, p + v3s16(0, 1, 0), light); lightSpread(a, p + v3s16(1, 0, 0), light); @@ -256,15 +241,43 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { } -void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { - VoxelArea a(nmin, nmax); - bool block_is_underground = (water_level >= nmax.Y); +void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax) +{ + ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG); + //TimeTaker t("updateLighting"); + + propagateSunlight(nmin, nmax); + spreadLight(full_nmin, full_nmax); + + //printf("updateLighting: %dms\n", t.stop()); +} + + +void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) +{ ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG); //TimeTaker t("updateLighting"); - // first, send vertical rays of sunshine downward + propagateSunlight( + nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE, + nmax + v3s16(1, 0, 1) * MAP_BLOCKSIZE); + + spreadLight( + nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE, + nmax + v3s16(1, 1, 1) * MAP_BLOCKSIZE); + + //printf("updateLighting: %dms\n", t.stop()); +} + + +void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax) +{ + //TimeTaker t("propagateSunlight"); + VoxelArea a(nmin, nmax); + bool block_is_underground = (water_level >= nmax.Y); v3s16 em = vm->m_area.getExtent(); + for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) { for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) { // see if we can get a light value from the overtop @@ -286,8 +299,17 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { } } } - - // now spread the sunlight and light up any sources + //printf("propagateSunlight: %dms\n", t.stop()); +} + + + +void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax) +{ + //TimeTaker t("spreadLight"); + VoxelArea a(nmin, nmax); + v3s16 em = vm->m_area.getExtent(); + for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) { for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) { u32 i = vm->m_area.index(a.MinEdge.X, y, z); @@ -296,11 +318,11 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { if (n.getContent() == CONTENT_IGNORE || !ndef->get(n).light_propagates) continue; - + u8 light_produced = ndef->get(n).light_source & 0x0F; if (light_produced) n.param1 = light_produced; - + u8 light = n.param1 & 0x0F; if (light) { lightSpread(a, v3s16(x, y, z + 1), light); @@ -313,26 +335,28 @@ void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax) { } } } - - //printf("updateLighting: %dms\n", t.stop()); + + //printf("spreadLight: %dms\n", t.stop()); } -void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) { + +void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) +{ enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT}; VoxelArea a(nmin, nmax); bool block_is_underground = (water_level > nmax.Y); bool sunlight = !block_is_underground; ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG); - + for (int i = 0; i < 2; i++) { enum LightBank bank = banks[i]; std::set light_sources; std::map unlight_from; voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef, - light_sources, unlight_from); + light_sources, unlight_from); voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef); vm->unspreadLight(bank, unlight_from, light_sources, ndef); @@ -341,102 +365,150 @@ void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax) { } -//////////////////////// Mapgen V6 parameter read/write - -bool MapgenV6Params::readParams(Settings *settings) { - freq_desert = settings->getFloat("mgv6_freq_desert"); - freq_beach = settings->getFloat("mgv6_freq_beach"); - - np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base"); - np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher"); - np_steepness = settings->getNoiseParams("mgv6_np_steepness"); - np_height_select = settings->getNoiseParams("mgv6_np_height_select"); - np_mud = settings->getNoiseParams("mgv6_np_mud"); - np_beach = settings->getNoiseParams("mgv6_np_beach"); - np_biome = settings->getNoiseParams("mgv6_np_biome"); - np_cave = settings->getNoiseParams("mgv6_np_cave"); - np_humidity = settings->getNoiseParams("mgv6_np_humidity"); - np_trees = settings->getNoiseParams("mgv6_np_trees"); - np_apple_trees = settings->getNoiseParams("mgv6_np_apple_trees"); - - bool success = - np_terrain_base && np_terrain_higher && np_steepness && - np_height_select && np_trees && np_mud && - np_beach && np_biome && np_cave && - np_humidity && np_apple_trees; - return success; +/////////////////////////////////////////////////////////////////////////////// + +GenerateNotifier::GenerateNotifier() +{ + m_notify_on = 0; } -void MapgenV6Params::writeParams(Settings *settings) { - settings->setFloat("mgv6_freq_desert", freq_desert); - settings->setFloat("mgv6_freq_beach", freq_beach); - - settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base); - settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher); - settings->setNoiseParams("mgv6_np_steepness", np_steepness); - settings->setNoiseParams("mgv6_np_height_select", np_height_select); - settings->setNoiseParams("mgv6_np_mud", np_mud); - settings->setNoiseParams("mgv6_np_beach", np_beach); - settings->setNoiseParams("mgv6_np_biome", np_biome); - settings->setNoiseParams("mgv6_np_cave", np_cave); - settings->setNoiseParams("mgv6_np_humidity", np_humidity); - settings->setNoiseParams("mgv6_np_trees", np_trees); - settings->setNoiseParams("mgv6_np_apple_trees", np_apple_trees); +GenerateNotifier::GenerateNotifier(u32 notify_on, + std::set *notify_on_deco_ids) +{ + m_notify_on = notify_on; + m_notify_on_deco_ids = notify_on_deco_ids; } -bool MapgenV7Params::readParams(Settings *settings) { - np_terrain_base = settings->getNoiseParams("mgv7_np_terrain_base"); - np_terrain_alt = settings->getNoiseParams("mgv7_np_terrain_alt"); - np_terrain_mod = settings->getNoiseParams("mgv7_np_terrain_mod"); - np_terrain_persist = settings->getNoiseParams("mgv7_np_terrain_persist"); - np_height_select = settings->getNoiseParams("mgv7_np_height_select"); - np_ridge = settings->getNoiseParams("mgv7_np_ridge"); - - bool success = - np_terrain_base && np_terrain_alt && np_terrain_mod && - np_terrain_persist && np_height_select && np_ridge; - return success; +void GenerateNotifier::setNotifyOn(u32 notify_on) +{ + m_notify_on = notify_on; } -void MapgenV7Params::writeParams(Settings *settings) { - settings->setNoiseParams("mgv7_np_terrain_base", np_terrain_base); - settings->setNoiseParams("mgv7_np_terrain_alt", np_terrain_alt); - settings->setNoiseParams("mgv7_np_terrain_mod", np_terrain_mod); - settings->setNoiseParams("mgv7_np_terrain_persist", np_terrain_persist); - settings->setNoiseParams("mgv7_np_height_select", np_height_select); - settings->setNoiseParams("mgv7_np_ridge", np_ridge); +void GenerateNotifier::setNotifyOnDecoIds(std::set *notify_on_deco_ids) +{ + m_notify_on_deco_ids = notify_on_deco_ids; } -/////////////////////////////////// legacy static functions for farmesh +bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id) +{ + if (!(m_notify_on & (1 << type))) + return false; + + if (type == GENNOTIFY_DECORATION && + m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end()) + return false; + GenNotifyEvent gne; + gne.type = type; + gne.pos = pos; + gne.id = id; + m_notify_events.push_back(gne); -s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) { - //just need to return something - s16 level = 5; - return level; + return true; } -bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) { - double sandnoise = noise2d_perlin( - 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250, - seed+59420, 3, 0.50); +void GenerateNotifier::getEvents( + std::map > &event_map, + bool peek_events) +{ + std::list::iterator it; + + for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) { + GenNotifyEvent &gn = *it; + std::string name = (gn.type == GENNOTIFY_DECORATION) ? + "decoration#"+ itos(gn.id) : + flagdesc_gennotify[gn.type].name; + + event_map[name].push_back(gn.pos); + } + + if (!peek_events) + m_notify_events.clear(); +} + + +/////////////////////////////////////////////////////////////////////////////// + + +GenElementManager::GenElementManager(IGameDef *gamedef) +{ + m_ndef = gamedef->getNodeDefManager(); +} + + +GenElementManager::~GenElementManager() +{ + for (size_t i = 0; i != m_elements.size(); i++) + delete m_elements[i]; +} + + +u32 GenElementManager::add(GenElement *elem) +{ + size_t nelem = m_elements.size(); + + for (size_t i = 0; i != nelem; i++) { + if (m_elements[i] == NULL) { + elem->id = i; + m_elements[i] = elem; + return i; + } + } + + if (nelem >= this->ELEMENT_LIMIT) + return -1; + + elem->id = nelem; + m_elements.push_back(elem); + + verbosestream << "GenElementManager: added " << this->ELEMENT_TITLE + << " element '" << elem->name << "'" << std::endl; + + return nelem; +} + + +GenElement *GenElementManager::get(u32 id) +{ + return (id < m_elements.size()) ? m_elements[id] : NULL; +} + + +GenElement *GenElementManager::getByName(const std::string &name) +{ + for (size_t i = 0; i != m_elements.size(); i++) { + GenElement *elem = m_elements[i]; + if (elem && name == elem->name) + return elem; + } + + return NULL; +} + + +GenElement *GenElementManager::update(u32 id, GenElement *elem) +{ + if (id >= m_elements.size()) + return NULL; + + GenElement *old_elem = m_elements[id]; + m_elements[id] = elem; + return old_elem; +} + - return (sandnoise > 0.15); +GenElement *GenElementManager::remove(u32 id) +{ + return update(id, NULL); } -double Mapgen::tree_amount_2d(u64 seed, v2s16 p) { - double noise = noise2d_perlin( - 0.5+(float)p.X/125, 0.5+(float)p.Y/125, - seed+2, 4, 0.66); - double zeroval = -0.39; - if(noise < zeroval) - return 0; - else - return 0.04 * (noise-zeroval) / (1.0-zeroval); +void GenElementManager::clear() +{ + m_elements.clear(); }