LCOV - code coverage report
Current view: top level - src - mapgen.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 242 0.4 %
Date: 2015-07-11 18:23:49 Functions: 2 27 7.4 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2015 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
       4             : Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
       5             : 
       6             : This program is free software; you can redistribute it and/or modify
       7             : it under the terms of the GNU Lesser General Public License as published by
       8             : the Free Software Foundation; either version 2.1 of the License, or
       9             : (at your option) any later version.
      10             : 
      11             : This program is distributed in the hope that it will be useful,
      12             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             : GNU Lesser General Public License for more details.
      15             : 
      16             : You should have received a copy of the GNU Lesser General Public License along
      17             : with this program; if not, write to the Free Software Foundation, Inc.,
      18             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             : */
      20             : 
      21             : #include "mapgen.h"
      22             : #include "voxel.h"
      23             : #include "noise.h"
      24             : #include "gamedef.h"
      25             : #include "mg_biome.h"
      26             : #include "mapblock.h"
      27             : #include "mapnode.h"
      28             : #include "map.h"
      29             : #include "content_sao.h"
      30             : #include "nodedef.h"
      31             : #include "emerge.h"
      32             : #include "content_mapnode.h" // For content_mapnode_get_new_name
      33             : #include "voxelalgorithms.h"
      34             : #include "porting.h"
      35             : #include "profiler.h"
      36             : #include "settings.h"
      37             : #include "treegen.h"
      38             : #include "serialization.h"
      39             : #include "util/serialize.h"
      40             : #include "util/numeric.h"
      41             : #include "filesys.h"
      42             : #include "log.h"
      43             : 
      44             : FlagDesc flagdesc_mapgen[] = {
      45             :         {"trees",    MG_TREES},
      46             :         {"caves",    MG_CAVES},
      47             :         {"dungeons", MG_DUNGEONS},
      48             :         {"flat",     MG_FLAT},
      49             :         {"light",    MG_LIGHT},
      50             :         {NULL,       0}
      51             : };
      52             : 
      53             : FlagDesc flagdesc_gennotify[] = {
      54             :         {"dungeon",          1 << GENNOTIFY_DUNGEON},
      55             :         {"temple",           1 << GENNOTIFY_TEMPLE},
      56             :         {"cave_begin",       1 << GENNOTIFY_CAVE_BEGIN},
      57             :         {"cave_end",         1 << GENNOTIFY_CAVE_END},
      58             :         {"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
      59             :         {"large_cave_end",   1 << GENNOTIFY_LARGECAVE_END},
      60             :         {"decoration",       1 << GENNOTIFY_DECORATION},
      61             :         {NULL,               0}
      62             : };
      63             : 
      64             : 
      65             : ///////////////////////////////////////////////////////////////////////////////
      66             : 
      67             : 
      68           0 : Mapgen::Mapgen()
      69             : {
      70           0 :         generating  = false;
      71           0 :         id          = -1;
      72           0 :         seed        = 0;
      73           0 :         water_level = 0;
      74           0 :         flags       = 0;
      75             : 
      76           0 :         vm        = NULL;
      77           0 :         ndef      = NULL;
      78           0 :         heightmap = NULL;
      79           0 :         biomemap  = NULL;
      80           0 :         heatmap   = NULL;
      81           0 :         humidmap  = NULL;
      82           0 : }
      83             : 
      84             : 
      85           0 : Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
      86           0 :         gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
      87             : {
      88           0 :         generating  = false;
      89           0 :         id          = mapgenid;
      90           0 :         seed        = (int)params->seed;
      91           0 :         water_level = params->water_level;
      92           0 :         flags       = params->flags;
      93           0 :         csize       = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
      94             : 
      95           0 :         vm        = NULL;
      96           0 :         ndef      = NULL;
      97           0 :         heightmap = NULL;
      98           0 :         biomemap  = NULL;
      99           0 :         heatmap   = NULL;
     100           0 :         humidmap  = NULL;
     101           0 : }
     102             : 
     103             : 
     104           0 : Mapgen::~Mapgen()
     105             : {
     106           0 : }
     107             : 
     108             : 
     109           0 : u32 Mapgen::getBlockSeed(v3s16 p, int seed)
     110             : {
     111             :         return (u32)seed   +
     112           0 :                 p.Z * 38134234 +
     113           0 :                 p.Y * 42123    +
     114           0 :                 p.X * 23;
     115             : }
     116             : 
     117             : 
     118           0 : u32 Mapgen::getBlockSeed2(v3s16 p, int seed)
     119             : {
     120           0 :         u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
     121           0 :         n = (n >> 13) ^ n;
     122           0 :         return (n * (n * n * 60493 + 19990303) + 1376312589);
     123             : }
     124             : 
     125             : 
     126             : // Returns Y one under area minimum if not found
     127           0 : s16 Mapgen::findGroundLevelFull(v2s16 p2d)
     128             : {
     129           0 :         v3s16 em = vm->m_area.getExtent();
     130           0 :         s16 y_nodes_max = vm->m_area.MaxEdge.Y;
     131           0 :         s16 y_nodes_min = vm->m_area.MinEdge.Y;
     132           0 :         u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
     133             :         s16 y;
     134             : 
     135           0 :         for (y = y_nodes_max; y >= y_nodes_min; y--) {
     136           0 :                 MapNode &n = vm->m_data[i];
     137           0 :                 if (ndef->get(n).walkable)
     138           0 :                         break;
     139             : 
     140           0 :                 vm->m_area.add_y(em, i, -1);
     141             :         }
     142           0 :         return (y >= y_nodes_min) ? y : y_nodes_min - 1;
     143             : }
     144             : 
     145             : 
     146             : // Returns -MAP_GENERATION_LIMIT if not found
     147           0 : s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
     148             : {
     149           0 :         v3s16 em = vm->m_area.getExtent();
     150           0 :         u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
     151             :         s16 y;
     152             : 
     153           0 :         for (y = ymax; y >= ymin; y--) {
     154           0 :                 MapNode &n = vm->m_data[i];
     155           0 :                 if (ndef->get(n).walkable)
     156           0 :                         break;
     157             : 
     158           0 :                 vm->m_area.add_y(em, i, -1);
     159             :         }
     160           0 :         return (y >= ymin) ? y : -MAP_GENERATION_LIMIT;
     161             : }
     162             : 
     163             : 
     164           0 : void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
     165             : {
     166           0 :         if (!heightmap)
     167           0 :                 return;
     168             : 
     169             :         //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO);
     170           0 :         int index = 0;
     171           0 :         for (s16 z = nmin.Z; z <= nmax.Z; z++) {
     172           0 :                 for (s16 x = nmin.X; x <= nmax.X; x++, index++) {
     173           0 :                         s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
     174             : 
     175           0 :                         heightmap[index] = y;
     176             :                 }
     177             :         }
     178             :         //printf("updateHeightmap: %dus\n", t.stop());
     179             : }
     180             : 
     181             : 
     182           0 : void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
     183             : {
     184             :         bool isliquid, wasliquid;
     185           0 :         v3s16 em  = vm->m_area.getExtent();
     186             : 
     187           0 :         for (s16 z = nmin.Z; z <= nmax.Z; z++) {
     188           0 :                 for (s16 x = nmin.X; x <= nmax.X; x++) {
     189           0 :                         wasliquid = true;
     190             : 
     191           0 :                         u32 i = vm->m_area.index(x, nmax.Y, z);
     192           0 :                         for (s16 y = nmax.Y; y >= nmin.Y; y--) {
     193           0 :                                 isliquid = ndef->get(vm->m_data[i]).isLiquid();
     194             : 
     195             :                                 // there was a change between liquid and nonliquid, add to queue.
     196           0 :                                 if (isliquid != wasliquid)
     197           0 :                                         trans_liquid->push_back(v3s16(x, y, z));
     198             : 
     199           0 :                                 wasliquid = isliquid;
     200           0 :                                 vm->m_area.add_y(em, i, -1);
     201             :                         }
     202             :                 }
     203             :         }
     204           0 : }
     205             : 
     206             : 
     207           0 : void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
     208             : {
     209           0 :         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
     210           0 :         VoxelArea a(nmin, nmax);
     211             : 
     212           0 :         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
     213           0 :                 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
     214           0 :                         u32 i = vm->m_area.index(a.MinEdge.X, y, z);
     215           0 :                         for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
     216           0 :                                 vm->m_data[i].param1 = light;
     217             :                 }
     218             :         }
     219           0 : }
     220             : 
     221             : 
     222           0 : void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
     223             : {
     224           0 :         if (light <= 1 || !a.contains(p))
     225           0 :                 return;
     226             : 
     227           0 :         u32 vi = vm->m_area.index(p);
     228           0 :         MapNode &nn = vm->m_data[vi];
     229             : 
     230           0 :         light--;
     231             :         // should probably compare masked, but doesn't seem to make a difference
     232           0 :         if (light <= nn.param1 || !ndef->get(nn).light_propagates)
     233           0 :                 return;
     234             : 
     235           0 :         nn.param1 = light;
     236             : 
     237           0 :         lightSpread(a, p + v3s16(0, 0, 1), light);
     238           0 :         lightSpread(a, p + v3s16(0, 1, 0), light);
     239           0 :         lightSpread(a, p + v3s16(1, 0, 0), light);
     240           0 :         lightSpread(a, p - v3s16(0, 0, 1), light);
     241           0 :         lightSpread(a, p - v3s16(0, 1, 0), light);
     242           0 :         lightSpread(a, p - v3s16(1, 0, 0), light);
     243             : }
     244             : 
     245             : 
     246           0 : void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax)
     247             : {
     248           0 :         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
     249             :         //TimeTaker t("updateLighting");
     250             : 
     251           0 :         propagateSunlight(nmin, nmax);
     252           0 :         spreadLight(full_nmin, full_nmax);
     253             : 
     254             :         //printf("updateLighting: %dms\n", t.stop());
     255           0 : }
     256             : 
     257             : 
     258             : 
     259           0 : void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax)
     260             : {
     261           0 :         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
     262             :         //TimeTaker t("updateLighting");
     263             : 
     264             :         propagateSunlight(
     265           0 :                 nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
     266           0 :                 nmax + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
     267             : 
     268             :         spreadLight(
     269           0 :                 nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
     270           0 :                 nmax + v3s16(1, 1, 1) * MAP_BLOCKSIZE);
     271             : 
     272             :         //printf("updateLighting: %dms\n", t.stop());
     273           0 : }
     274             : 
     275             : 
     276           0 : void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax)
     277             : {
     278             :         //TimeTaker t("propagateSunlight");
     279           0 :         VoxelArea a(nmin, nmax);
     280           0 :         bool block_is_underground = (water_level >= nmax.Y);
     281           0 :         v3s16 em = vm->m_area.getExtent();
     282             : 
     283           0 :         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
     284           0 :                 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
     285             :                         // see if we can get a light value from the overtop
     286           0 :                         u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
     287           0 :                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
     288           0 :                                 if (block_is_underground)
     289           0 :                                         continue;
     290           0 :                         } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN) {
     291           0 :                                 continue;
     292             :                         }
     293           0 :                         vm->m_area.add_y(em, i, -1);
     294             : 
     295           0 :                         for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
     296           0 :                                 MapNode &n = vm->m_data[i];
     297           0 :                                 if (!ndef->get(n).sunlight_propagates)
     298           0 :                                         break;
     299           0 :                                 n.param1 = LIGHT_SUN;
     300           0 :                                 vm->m_area.add_y(em, i, -1);
     301             :                         }
     302             :                 }
     303             :         }
     304             :         //printf("propagateSunlight: %dms\n", t.stop());
     305           0 : }
     306             : 
     307             : 
     308             : 
     309           0 : void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
     310             : {
     311             :         //TimeTaker t("spreadLight");
     312           0 :         VoxelArea a(nmin, nmax);
     313             : 
     314           0 :         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
     315           0 :                 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
     316           0 :                         u32 i = vm->m_area.index(a.MinEdge.X, y, z);
     317           0 :                         for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
     318           0 :                                 MapNode &n = vm->m_data[i];
     319           0 :                                 if (n.getContent() == CONTENT_IGNORE ||
     320           0 :                                         !ndef->get(n).light_propagates)
     321           0 :                                         continue;
     322             : 
     323           0 :                                 u8 light_produced = ndef->get(n).light_source & 0x0F;
     324           0 :                                 if (light_produced)
     325           0 :                                         n.param1 = light_produced;
     326             : 
     327           0 :                                 u8 light = n.param1 & 0x0F;
     328           0 :                                 if (light) {
     329           0 :                                         lightSpread(a, v3s16(x,     y,     z + 1), light);
     330           0 :                                         lightSpread(a, v3s16(x,     y + 1, z    ), light);
     331           0 :                                         lightSpread(a, v3s16(x + 1, y,     z    ), light);
     332           0 :                                         lightSpread(a, v3s16(x,     y,     z - 1), light);
     333           0 :                                         lightSpread(a, v3s16(x,     y - 1, z    ), light);
     334           0 :                                         lightSpread(a, v3s16(x - 1, y,     z    ), light);
     335             :                                 }
     336             :                         }
     337             :                 }
     338             :         }
     339             : 
     340             :         //printf("spreadLight: %dms\n", t.stop());
     341           0 : }
     342             : 
     343             : 
     344             : 
     345           0 : void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax)
     346             : {
     347           0 :         enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
     348           0 :         VoxelArea a(nmin, nmax);
     349           0 :         bool block_is_underground = (water_level > nmax.Y);
     350           0 :         bool sunlight = !block_is_underground;
     351             : 
     352           0 :         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
     353             : 
     354           0 :         for (int i = 0; i < 2; i++) {
     355           0 :                 enum LightBank bank = banks[i];
     356           0 :                 std::set<v3s16> light_sources;
     357           0 :                 std::map<v3s16, u8> unlight_from;
     358             : 
     359           0 :                 voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef,
     360           0 :                         light_sources, unlight_from);
     361           0 :                 voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef);
     362             : 
     363           0 :                 vm->unspreadLight(bank, unlight_from, light_sources, ndef);
     364           0 :                 vm->spreadLight(bank, light_sources, ndef);
     365             :         }
     366           0 : }
     367             : 
     368             : 
     369             : ///////////////////////////////////////////////////////////////////////////////
     370             : 
     371           0 : GenerateNotifier::GenerateNotifier()
     372             : {
     373           0 :         m_notify_on = 0;
     374           0 : }
     375             : 
     376             : 
     377           0 : GenerateNotifier::GenerateNotifier(u32 notify_on,
     378           0 :         std::set<u32> *notify_on_deco_ids)
     379             : {
     380           0 :         m_notify_on = notify_on;
     381           0 :         m_notify_on_deco_ids = notify_on_deco_ids;
     382           0 : }
     383             : 
     384             : 
     385           0 : void GenerateNotifier::setNotifyOn(u32 notify_on)
     386             : {
     387           0 :         m_notify_on = notify_on;
     388           0 : }
     389             : 
     390             : 
     391           0 : void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
     392             : {
     393           0 :         m_notify_on_deco_ids = notify_on_deco_ids;
     394           0 : }
     395             : 
     396             : 
     397           0 : bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
     398             : {
     399           0 :         if (!(m_notify_on & (1 << type)))
     400           0 :                 return false;
     401             : 
     402           0 :         if (type == GENNOTIFY_DECORATION &&
     403           0 :                 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
     404           0 :                 return false;
     405             : 
     406           0 :         GenNotifyEvent gne;
     407           0 :         gne.type = type;
     408           0 :         gne.pos  = pos;
     409           0 :         gne.id   = id;
     410           0 :         m_notify_events.push_back(gne);
     411             : 
     412           0 :         return true;
     413             : }
     414             : 
     415             : 
     416           0 : void GenerateNotifier::getEvents(
     417             :         std::map<std::string, std::vector<v3s16> > &event_map,
     418             :         bool peek_events)
     419             : {
     420           0 :         std::list<GenNotifyEvent>::iterator it;
     421             : 
     422           0 :         for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
     423           0 :                 GenNotifyEvent &gn = *it;
     424           0 :                 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
     425           0 :                         "decoration#"+ itos(gn.id) :
     426           0 :                         flagdesc_gennotify[gn.type].name;
     427             : 
     428           0 :                 event_map[name].push_back(gn.pos);
     429             :         }
     430             : 
     431           0 :         if (!peek_events)
     432           0 :                 m_notify_events.clear();
     433           0 : }
     434             : 
     435             : ///////////////////////////////////////////////////////////////////////////////
     436             : 
     437           0 : void MapgenParams::load(const Settings &settings)
     438             : {
     439           0 :         std::string seed_str;
     440           0 :         const char *seed_name = (&settings == g_settings) ? "fixed_map_seed" : "seed";
     441             : 
     442           0 :         if (settings.getNoEx(seed_name, seed_str) && !seed_str.empty())
     443           0 :                 seed = read_seed(seed_str.c_str());
     444             :         else
     445           0 :                 myrand_bytes(&seed, sizeof(seed));
     446             : 
     447           0 :         settings.getNoEx("mg_name", mg_name);
     448           0 :         settings.getS16NoEx("water_level", water_level);
     449           0 :         settings.getS16NoEx("chunksize", chunksize);
     450           0 :         settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
     451           0 :         settings.getNoiseParams("mg_biome_np_heat", np_biome_heat);
     452           0 :         settings.getNoiseParams("mg_biome_np_heat_blend", np_biome_heat_blend);
     453           0 :         settings.getNoiseParams("mg_biome_np_humidity", np_biome_humidity);
     454           0 :         settings.getNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend);
     455             : 
     456           0 :         delete sparams;
     457           0 :         sparams = EmergeManager::createMapgenParams(mg_name);
     458           0 :         if (sparams)
     459           0 :                 sparams->readParams(&settings);
     460           0 : }
     461             : 
     462             : 
     463           0 : void MapgenParams::save(Settings &settings) const
     464             : {
     465           0 :         settings.set("mg_name", mg_name);
     466           0 :         settings.setU64("seed", seed);
     467           0 :         settings.setS16("water_level", water_level);
     468           0 :         settings.setS16("chunksize", chunksize);
     469           0 :         settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, (u32)-1);
     470           0 :         settings.setNoiseParams("mg_biome_np_heat", np_biome_heat);
     471           0 :         settings.setNoiseParams("mg_biome_np_heat_blend", np_biome_heat_blend);
     472           0 :         settings.setNoiseParams("mg_biome_np_humidity", np_biome_humidity);
     473           0 :         settings.setNoiseParams("mg_biome_np_humidity_blend", np_biome_humidity_blend);
     474             : 
     475           0 :         if (sparams)
     476           0 :                 sparams->writeParams(&settings);
     477           3 : }
     478             : 

Generated by: LCOV version 1.11