Move globals from main.cpp to more sane locations
[oweals/minetest.git] / src / mapgen.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "mapgen.h"
21 #include "voxel.h"
22 #include "noise.h"
23 #include "gamedef.h"
24 #include "mg_biome.h"
25 #include "mapblock.h"
26 #include "mapnode.h"
27 #include "map.h"
28 #include "content_sao.h"
29 #include "nodedef.h"
30 #include "emerge.h"
31 #include "content_mapnode.h" // For content_mapnode_get_new_name
32 #include "voxelalgorithms.h"
33 #include "profiler.h"
34 #include "settings.h"
35 #include "treegen.h"
36 #include "serialization.h"
37 #include "util/serialize.h"
38 #include "util/numeric.h"
39 #include "filesys.h"
40 #include "log.h"
41
42 FlagDesc flagdesc_mapgen[] = {
43         {"trees",    MG_TREES},
44         {"caves",    MG_CAVES},
45         {"dungeons", MG_DUNGEONS},
46         {"flat",     MG_FLAT},
47         {"light",    MG_LIGHT},
48         {NULL,       0}
49 };
50
51 FlagDesc flagdesc_gennotify[] = {
52         {"dungeon",          1 << GENNOTIFY_DUNGEON},
53         {"temple",           1 << GENNOTIFY_TEMPLE},
54         {"cave_begin",       1 << GENNOTIFY_CAVE_BEGIN},
55         {"cave_end",         1 << GENNOTIFY_CAVE_END},
56         {"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
57         {"large_cave_end",   1 << GENNOTIFY_LARGECAVE_END},
58         {"decoration",       1 << GENNOTIFY_DECORATION},
59         {NULL,               0}
60 };
61
62
63 ///////////////////////////////////////////////////////////////////////////////
64
65
66 Mapgen::Mapgen()
67 {
68         generating    = false;
69         id            = -1;
70         seed          = 0;
71         water_level   = 0;
72         flags         = 0;
73
74         vm          = NULL;
75         ndef        = NULL;
76         heightmap   = NULL;
77         biomemap    = NULL;
78 }
79
80
81 Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
82         gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
83 {
84         generating    = false;
85         id            = mapgenid;
86         seed          = (int)params->seed;
87         water_level   = params->water_level;
88         flags         = params->flags;
89         csize         = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
90
91         vm        = NULL;
92         ndef      = NULL;
93         heightmap = NULL;
94         biomemap  = NULL;
95 }
96
97
98 Mapgen::~Mapgen()
99 {
100 }
101
102
103 u32 Mapgen::getBlockSeed(v3s16 p, int seed)
104 {
105         return (u32)seed   +
106                 p.Z * 38134234 +
107                 p.Y * 42123    +
108                 p.X * 23;
109 }
110
111
112 u32 Mapgen::getBlockSeed2(v3s16 p, int seed)
113 {
114         u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
115         n = (n >> 13) ^ n;
116         return (n * (n * n * 60493 + 19990303) + 1376312589);
117 }
118
119
120 // Returns Y one under area minimum if not found
121 s16 Mapgen::findGroundLevelFull(v2s16 p2d)
122 {
123         v3s16 em = vm->m_area.getExtent();
124         s16 y_nodes_max = vm->m_area.MaxEdge.Y;
125         s16 y_nodes_min = vm->m_area.MinEdge.Y;
126         u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
127         s16 y;
128
129         for (y = y_nodes_max; y >= y_nodes_min; y--) {
130                 MapNode &n = vm->m_data[i];
131                 if (ndef->get(n).walkable)
132                         break;
133
134                 vm->m_area.add_y(em, i, -1);
135         }
136         return (y >= y_nodes_min) ? y : y_nodes_min - 1;
137 }
138
139
140 // Returns -MAP_GENERATION_LIMIT if not found
141 s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
142 {
143         v3s16 em = vm->m_area.getExtent();
144         u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
145         s16 y;
146
147         for (y = ymax; y >= ymin; y--) {
148                 MapNode &n = vm->m_data[i];
149                 if (ndef->get(n).walkable)
150                         break;
151
152                 vm->m_area.add_y(em, i, -1);
153         }
154         return (y >= ymin) ? y : -MAP_GENERATION_LIMIT;
155 }
156
157
158 void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
159 {
160         if (!heightmap)
161                 return;
162
163         //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO);
164         int index = 0;
165         for (s16 z = nmin.Z; z <= nmax.Z; z++) {
166                 for (s16 x = nmin.X; x <= nmax.X; x++, index++) {
167                         s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
168
169                         heightmap[index] = y;
170                 }
171         }
172         //printf("updateHeightmap: %dus\n", t.stop());
173 }
174
175
176 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
177 {
178         bool isliquid, wasliquid;
179         v3s16 em  = vm->m_area.getExtent();
180
181         for (s16 z = nmin.Z; z <= nmax.Z; z++) {
182                 for (s16 x = nmin.X; x <= nmax.X; x++) {
183                         wasliquid = true;
184
185                         u32 i = vm->m_area.index(x, nmax.Y, z);
186                         for (s16 y = nmax.Y; y >= nmin.Y; y--) {
187                                 isliquid = ndef->get(vm->m_data[i]).isLiquid();
188
189                                 // there was a change between liquid and nonliquid, add to queue.
190                                 if (isliquid != wasliquid)
191                                         trans_liquid->push_back(v3s16(x, y, z));
192
193                                 wasliquid = isliquid;
194                                 vm->m_area.add_y(em, i, -1);
195                         }
196                 }
197         }
198 }
199
200
201 void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
202 {
203         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
204         VoxelArea a(nmin, nmax);
205
206         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
207                 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
208                         u32 i = vm->m_area.index(a.MinEdge.X, y, z);
209                         for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
210                                 vm->m_data[i].param1 = light;
211                 }
212         }
213 }
214
215
216 void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
217 {
218         if (light <= 1 || !a.contains(p))
219                 return;
220
221         u32 vi = vm->m_area.index(p);
222         MapNode &nn = vm->m_data[vi];
223
224         light--;
225         // should probably compare masked, but doesn't seem to make a difference
226         if (light <= nn.param1 || !ndef->get(nn).light_propagates)
227                 return;
228
229         nn.param1 = light;
230
231         lightSpread(a, p + v3s16(0, 0, 1), light);
232         lightSpread(a, p + v3s16(0, 1, 0), light);
233         lightSpread(a, p + v3s16(1, 0, 0), light);
234         lightSpread(a, p - v3s16(0, 0, 1), light);
235         lightSpread(a, p - v3s16(0, 1, 0), light);
236         lightSpread(a, p - v3s16(1, 0, 0), light);
237 }
238
239
240 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax)
241 {
242         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
243         //TimeTaker t("updateLighting");
244
245         propagateSunlight(nmin, nmax);
246         spreadLight(full_nmin, full_nmax);
247
248         //printf("updateLighting: %dms\n", t.stop());
249 }
250
251
252
253 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax)
254 {
255         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
256         //TimeTaker t("updateLighting");
257
258         propagateSunlight(
259                 nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
260                 nmax + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
261
262         spreadLight(
263                 nmin - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
264                 nmax + v3s16(1, 1, 1) * MAP_BLOCKSIZE);
265
266         //printf("updateLighting: %dms\n", t.stop());
267 }
268
269
270 void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax)
271 {
272         //TimeTaker t("propagateSunlight");
273         VoxelArea a(nmin, nmax);
274         bool block_is_underground = (water_level >= nmax.Y);
275         v3s16 em = vm->m_area.getExtent();
276
277         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
278                 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
279                         // see if we can get a light value from the overtop
280                         u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
281                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
282                                 if (block_is_underground)
283                                         continue;
284                         } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN) {
285                                 continue;
286                         }
287                         vm->m_area.add_y(em, i, -1);
288
289                         for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
290                                 MapNode &n = vm->m_data[i];
291                                 if (!ndef->get(n).sunlight_propagates)
292                                         break;
293                                 n.param1 = LIGHT_SUN;
294                                 vm->m_area.add_y(em, i, -1);
295                         }
296                 }
297         }
298         //printf("propagateSunlight: %dms\n", t.stop());
299 }
300
301
302
303 void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
304 {
305         //TimeTaker t("spreadLight");
306         VoxelArea a(nmin, nmax);
307
308         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
309                 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
310                         u32 i = vm->m_area.index(a.MinEdge.X, y, z);
311                         for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
312                                 MapNode &n = vm->m_data[i];
313                                 if (n.getContent() == CONTENT_IGNORE ||
314                                         !ndef->get(n).light_propagates)
315                                         continue;
316
317                                 u8 light_produced = ndef->get(n).light_source & 0x0F;
318                                 if (light_produced)
319                                         n.param1 = light_produced;
320
321                                 u8 light = n.param1 & 0x0F;
322                                 if (light) {
323                                         lightSpread(a, v3s16(x,     y,     z + 1), light);
324                                         lightSpread(a, v3s16(x,     y + 1, z    ), light);
325                                         lightSpread(a, v3s16(x + 1, y,     z    ), light);
326                                         lightSpread(a, v3s16(x,     y,     z - 1), light);
327                                         lightSpread(a, v3s16(x,     y - 1, z    ), light);
328                                         lightSpread(a, v3s16(x - 1, y,     z    ), light);
329                                 }
330                         }
331                 }
332         }
333
334         //printf("spreadLight: %dms\n", t.stop());
335 }
336
337
338
339 void Mapgen::calcLightingOld(v3s16 nmin, v3s16 nmax)
340 {
341         enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
342         VoxelArea a(nmin, nmax);
343         bool block_is_underground = (water_level > nmax.Y);
344         bool sunlight = !block_is_underground;
345
346         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
347
348         for (int i = 0; i < 2; i++) {
349                 enum LightBank bank = banks[i];
350                 std::set<v3s16> light_sources;
351                 std::map<v3s16, u8> unlight_from;
352
353                 voxalgo::clearLightAndCollectSources(*vm, a, bank, ndef,
354                         light_sources, unlight_from);
355                 voxalgo::propagateSunlight(*vm, a, sunlight, light_sources, ndef);
356
357                 vm->unspreadLight(bank, unlight_from, light_sources, ndef);
358                 vm->spreadLight(bank, light_sources, ndef);
359         }
360 }
361
362
363 ///////////////////////////////////////////////////////////////////////////////
364
365 GenerateNotifier::GenerateNotifier()
366 {
367         m_notify_on = 0;
368 }
369
370
371 GenerateNotifier::GenerateNotifier(u32 notify_on,
372         std::set<u32> *notify_on_deco_ids)
373 {
374         m_notify_on = notify_on;
375         m_notify_on_deco_ids = notify_on_deco_ids;
376 }
377
378
379 void GenerateNotifier::setNotifyOn(u32 notify_on)
380 {
381         m_notify_on = notify_on;
382 }
383
384
385 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
386 {
387         m_notify_on_deco_ids = notify_on_deco_ids;
388 }
389
390
391 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
392 {
393         if (!(m_notify_on & (1 << type)))
394                 return false;
395
396         if (type == GENNOTIFY_DECORATION &&
397                 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
398                 return false;
399
400         GenNotifyEvent gne;
401         gne.type = type;
402         gne.pos  = pos;
403         gne.id   = id;
404         m_notify_events.push_back(gne);
405
406         return true;
407 }
408
409
410 void GenerateNotifier::getEvents(
411         std::map<std::string, std::vector<v3s16> > &event_map,
412         bool peek_events)
413 {
414         std::list<GenNotifyEvent>::iterator it;
415
416         for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
417                 GenNotifyEvent &gn = *it;
418                 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
419                         "decoration#"+ itos(gn.id) :
420                         flagdesc_gennotify[gn.type].name;
421
422                 event_map[name].push_back(gn.pos);
423         }
424
425         if (!peek_events)
426                 m_notify_events.clear();
427 }
428
429
430 ///////////////////////////////////////////////////////////////////////////////
431
432
433 ObjDefManager::ObjDefManager(IGameDef *gamedef, ObjDefType type)
434 {
435         m_objtype = type;
436         m_ndef = gamedef->getNodeDefManager();
437 }
438
439
440 ObjDefManager::~ObjDefManager()
441 {
442         for (size_t i = 0; i != m_objects.size(); i++)
443                 delete m_objects[i];
444 }
445
446
447 ObjDefHandle ObjDefManager::add(ObjDef *obj)
448 {
449         assert(obj);
450
451         if (obj->name.length() && getByName(obj->name))
452                 return OBJDEF_INVALID_HANDLE;
453
454         u32 index = addRaw(obj);
455         if (index == OBJDEF_INVALID_INDEX)
456                 return OBJDEF_INVALID_HANDLE;
457
458         obj->handle = createHandle(index, m_objtype, obj->uid);
459         return obj->handle;
460 }
461
462
463 ObjDef *ObjDefManager::get(ObjDefHandle handle) const
464 {
465         u32 index = validateHandle(handle);
466         return (index != OBJDEF_INVALID_INDEX) ? getRaw(index) : NULL;
467 }
468
469
470 ObjDef *ObjDefManager::set(ObjDefHandle handle, ObjDef *obj)
471 {
472         u32 index = validateHandle(handle);
473         return (index != OBJDEF_INVALID_INDEX) ? setRaw(index, obj) : NULL;
474 }
475
476
477 u32 ObjDefManager::addRaw(ObjDef *obj)
478 {
479         size_t nobjects = m_objects.size();
480         if (nobjects >= OBJDEF_MAX_ITEMS)
481                 return -1;
482
483         obj->index = nobjects;
484
485         // Ensure UID is nonzero so that a valid handle == OBJDEF_INVALID_HANDLE
486         // is not possible.  The slight randomness bias isn't very significant.
487         obj->uid = myrand() & OBJDEF_UID_MASK;
488         if (obj->uid == 0)
489                 obj->uid = 1;
490
491         m_objects.push_back(obj);
492
493         infostream << "ObjDefManager: added " << getObjectTitle()
494                 << ": name=\"" << obj->name
495                 << "\" index=" << obj->index
496                 << " uid="     << obj->uid
497                 << std::endl;
498
499         return nobjects;
500 }
501
502
503 ObjDef *ObjDefManager::getRaw(u32 index) const
504 {
505         return m_objects[index];
506 }
507
508
509 ObjDef *ObjDefManager::setRaw(u32 index, ObjDef *obj)
510 {
511         ObjDef *old_obj = m_objects[index];
512         m_objects[index] = obj;
513         return old_obj;
514 }
515
516
517 ObjDef *ObjDefManager::getByName(const std::string &name) const
518 {
519         for (size_t i = 0; i != m_objects.size(); i++) {
520                 ObjDef *obj = m_objects[i];
521                 if (obj && !strcasecmp(name.c_str(), obj->name.c_str()))
522                         return obj;
523         }
524
525         return NULL;
526 }
527
528
529 void ObjDefManager::clear()
530 {
531         for (size_t i = 0; i != m_objects.size(); i++)
532                 delete m_objects[i];
533
534         m_objects.clear();
535 }
536
537
538 u32 ObjDefManager::validateHandle(ObjDefHandle handle) const
539 {
540         ObjDefType type;
541         u32 index;
542         u32 uid;
543
544         bool is_valid =
545                 (handle != OBJDEF_INVALID_HANDLE)         &&
546                 decodeHandle(handle, &index, &type, &uid) &&
547                 (type == m_objtype)                       &&
548                 (index < m_objects.size())                &&
549                 (m_objects[index]->uid == uid);
550
551         return is_valid ? index : -1;
552 }
553
554
555 ObjDefHandle ObjDefManager::createHandle(u32 index, ObjDefType type, u32 uid)
556 {
557         ObjDefHandle handle = 0;
558         set_bits(&handle, 0, 18, index);
559         set_bits(&handle, 18, 6, type);
560         set_bits(&handle, 24, 7, uid);
561
562         u32 parity = calc_parity(handle);
563         set_bits(&handle, 31, 1, parity);
564
565         return handle ^ OBJDEF_HANDLE_SALT;
566 }
567
568
569 bool ObjDefManager::decodeHandle(ObjDefHandle handle, u32 *index,
570         ObjDefType *type, u32 *uid)
571 {
572         handle ^= OBJDEF_HANDLE_SALT;
573
574         u32 parity = get_bits(handle, 31, 1);
575         set_bits(&handle, 31, 1, 0);
576         if (parity != calc_parity(handle))
577                 return false;
578
579         *index = get_bits(handle, 0, 18);
580         *type  = (ObjDefType)get_bits(handle, 18, 6);
581         *uid   = get_bits(handle, 24, 7);
582         return true;
583 }
584
585
586 ///////////////////////////////////////////////////////////////////////////////
587
588
589 void MapgenParams::load(const Settings &settings)
590 {
591         std::string seed_str;
592         const char *seed_name = (&settings == g_settings) ? "fixed_map_seed" : "seed";
593
594         if (settings.getNoEx(seed_name, seed_str) && !seed_str.empty())
595                 seed = read_seed(seed_str.c_str());
596         else
597                 myrand_bytes(&seed, sizeof(seed));
598
599         settings.getNoEx("mg_name", mg_name);
600         settings.getS16NoEx("water_level", water_level);
601         settings.getS16NoEx("chunksize", chunksize);
602         settings.getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
603         settings.getNoiseParams("mg_biome_np_heat", np_biome_heat);
604         settings.getNoiseParams("mg_biome_np_humidity", np_biome_humidity);
605
606         delete sparams;
607         sparams = EmergeManager::createMapgenParams(mg_name);
608         if (sparams)
609                 sparams->readParams(&settings);
610 }
611
612
613 void MapgenParams::save(Settings &settings) const
614 {
615         settings.set("mg_name", mg_name);
616         settings.setU64("seed", seed);
617         settings.setS16("water_level", water_level);
618         settings.setS16("chunksize", chunksize);
619         settings.setFlagStr("mg_flags", flags, flagdesc_mapgen, (u32)-1);
620         settings.setNoiseParams("mg_biome_np_heat", np_biome_heat);
621         settings.setNoiseParams("mg_biome_np_humidity", np_biome_humidity);
622
623         if (sparams)
624                 sparams->writeParams(&settings);
625 }
626