X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmapgen.cpp;h=3f83d21785757042960442886586453e4ca42f32;hb=63867b1a372a4d1a4a4ffdec9d0862b094211a89;hp=699b51789af3619b0a934e808dc488342045a9ac;hpb=1f1ad9fd23b07a1c1b5477ee0dbf2c4fdaabccef;p=minetest.git diff --git a/src/mapgen.cpp b/src/mapgen.cpp index 699b51789..3f83d2178 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -20,48 +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 "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_forests", MGV6_FORESTS}, - {"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_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; +} + + +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; +} + + +Mapgen::~Mapgen() +{ +} + + +u32 Mapgen::getBlockSeed(v3s16 p, int seed) +{ + return (u32)seed + + p.Z * 38134234 + + p.Y * 42123 + + p.X * 23; +} + + +u32 Mapgen::getBlockSeed2(v3s16 p, int seed) +{ + return noise3d(p.X, p.Y, p.Z, seed); +} + + +// 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; +} + + +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); + } + return y; +} + -void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nmax) { +void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) +{ + if (!heightmap) + return; + + //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO); + int index = 0; + 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 (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) +{ 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)); @@ -73,10 +202,10 @@ 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 - v3s16(1,0,1) * MAP_BLOCKSIZE, - nmax + v3s16(1,0,1) * MAP_BLOCKSIZE); + VoxelArea a(nmin, nmax); for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) { for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) { @@ -88,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]; @@ -99,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); @@ -111,16 +241,43 @@ void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light) { } -void Mapgen::updateLighting(v3s16 nmin, v3s16 nmax) { - VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE, - nmax + v3s16(1,0,1) * MAP_BLOCKSIZE); - 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 @@ -142,8 +299,17 @@ void Mapgen::updateLighting(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); @@ -152,11 +318,11 @@ void Mapgen::updateLighting(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); @@ -169,28 +335,28 @@ void Mapgen::updateLighting(v3s16 nmin, v3s16 nmax) { } } } - - //printf("updateLighting: %dms\n", t.stop()); + + //printf("spreadLight: %dms\n", t.stop()); } -void Mapgen::updateLightingOld(v3s16 nmin, v3s16 nmax) { - enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT}; - VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE, - nmax + v3s16(1,0,1) * MAP_BLOCKSIZE); +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); @@ -199,72 +365,150 @@ void Mapgen::updateLightingOld(v3s16 nmin, v3s16 nmax) { } -//////////////////////// Mapgen V6 parameter read/write +/////////////////////////////////////////////////////////////////////////////// + +GenerateNotifier::GenerateNotifier() +{ + m_notify_on = 0; +} + + +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; +} + + +void GenerateNotifier::setNotifyOn(u32 notify_on) +{ + m_notify_on = notify_on; +} + + +void GenerateNotifier::setNotifyOnDecoIds(std::set *notify_on_deco_ids) +{ + m_notify_on_deco_ids = notify_on_deco_ids; +} + + +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); + + return true; +} + + +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(); +} + + +/////////////////////////////////////////////////////////////////////////////// + -bool MapgenV6Params::readParams(Settings *settings) { - freq_desert = settings->getFloat("mgv6_freq_desert"); - freq_beach = settings->getFloat("mgv6_freq_beach"); +GenElementManager::GenElementManager(IGameDef *gamedef) +{ + m_ndef = gamedef->getNodeDefManager(); +} - 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_trees = settings->getNoiseParams("mgv6_np_trees"); - 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"); - bool success = - np_terrain_base && np_terrain_higher && np_steepness && - np_height_select && np_trees && np_mud && - np_beach && np_biome && np_cave; - return success; +GenElementManager::~GenElementManager() +{ + for (size_t i = 0; i != m_elements.size(); i++) + delete m_elements[i]; } -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_trees", np_trees); - 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); +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; } -/////////////////////////////////// legacy static functions for farmesh +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; + } -s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) { - //just need to return something - s16 level = 5; - return level; + return NULL; } -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); +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(); }