]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Add MapSettingsManager and new mapgen setting script API functions
[dragonfireclient.git] / src / map.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 "map.h"
21 #include "mapsector.h"
22 #include "mapblock.h"
23 #include "filesys.h"
24 #include "voxel.h"
25 #include "porting.h"
26 #include "serialization.h"
27 #include "nodemetadata.h"
28 #include "settings.h"
29 #include "log.h"
30 #include "profiler.h"
31 #include "nodedef.h"
32 #include "gamedef.h"
33 #include "util/directiontables.h"
34 #include "util/mathconstants.h"
35 #include "rollback_interface.h"
36 #include "environment.h"
37 #include "emerge.h"
38 #include "mapgen_v6.h"
39 #include "mg_biome.h"
40 #include "config.h"
41 #include "server.h"
42 #include "database.h"
43 #include "database-dummy.h"
44 #include "database-sqlite3.h"
45 #include <deque>
46 #include <queue>
47 #if USE_LEVELDB
48 #include "database-leveldb.h"
49 #endif
50 #if USE_REDIS
51 #include "database-redis.h"
52 #endif
53 #if USE_POSTGRESQL
54 #include "database-postgresql.h"
55 #endif
56
57 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
58
59
60 /*
61         Map
62 */
63
64 Map::Map(std::ostream &dout, IGameDef *gamedef):
65         m_dout(dout),
66         m_gamedef(gamedef),
67         m_sector_cache(NULL),
68         m_transforming_liquid_loop_count_multiplier(1.0f),
69         m_unprocessed_count(0),
70         m_inc_trending_up_start_time(0),
71         m_queue_size_timer_started(false)
72 {
73 }
74
75 Map::~Map()
76 {
77         /*
78                 Free all MapSectors
79         */
80         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
81                 i != m_sectors.end(); ++i)
82         {
83                 delete i->second;
84         }
85 }
86
87 void Map::addEventReceiver(MapEventReceiver *event_receiver)
88 {
89         m_event_receivers.insert(event_receiver);
90 }
91
92 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
93 {
94         m_event_receivers.erase(event_receiver);
95 }
96
97 void Map::dispatchEvent(MapEditEvent *event)
98 {
99         for(std::set<MapEventReceiver*>::iterator
100                         i = m_event_receivers.begin();
101                         i != m_event_receivers.end(); ++i)
102         {
103                 (*i)->onMapEditEvent(event);
104         }
105 }
106
107 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
108 {
109         if(m_sector_cache != NULL && p == m_sector_cache_p){
110                 MapSector * sector = m_sector_cache;
111                 return sector;
112         }
113
114         std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
115
116         if(n == m_sectors.end())
117                 return NULL;
118
119         MapSector *sector = n->second;
120
121         // Cache the last result
122         m_sector_cache_p = p;
123         m_sector_cache = sector;
124
125         return sector;
126 }
127
128 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
129 {
130         return getSectorNoGenerateNoExNoLock(p);
131 }
132
133 MapSector * Map::getSectorNoGenerate(v2s16 p)
134 {
135         MapSector *sector = getSectorNoGenerateNoEx(p);
136         if(sector == NULL)
137                 throw InvalidPositionException();
138
139         return sector;
140 }
141
142 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
143 {
144         v2s16 p2d(p3d.X, p3d.Z);
145         MapSector * sector = getSectorNoGenerateNoEx(p2d);
146         if(sector == NULL)
147                 return NULL;
148         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
149         return block;
150 }
151
152 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
153 {
154         MapBlock *block = getBlockNoCreateNoEx(p3d);
155         if(block == NULL)
156                 throw InvalidPositionException();
157         return block;
158 }
159
160 bool Map::isNodeUnderground(v3s16 p)
161 {
162         v3s16 blockpos = getNodeBlockPos(p);
163         try{
164                 MapBlock * block = getBlockNoCreate(blockpos);
165                 return block->getIsUnderground();
166         }
167         catch(InvalidPositionException &e)
168         {
169                 return false;
170         }
171 }
172
173 bool Map::isValidPosition(v3s16 p)
174 {
175         v3s16 blockpos = getNodeBlockPos(p);
176         MapBlock *block = getBlockNoCreate(blockpos);
177         return (block != NULL);
178 }
179
180 // Returns a CONTENT_IGNORE node if not found
181 MapNode Map::getNodeNoEx(v3s16 p, bool *is_valid_position)
182 {
183         v3s16 blockpos = getNodeBlockPos(p);
184         MapBlock *block = getBlockNoCreateNoEx(blockpos);
185         if (block == NULL) {
186                 if (is_valid_position != NULL)
187                         *is_valid_position = false;
188                 return MapNode(CONTENT_IGNORE);
189         }
190
191         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
192         bool is_valid_p;
193         MapNode node = block->getNodeNoCheck(relpos, &is_valid_p);
194         if (is_valid_position != NULL)
195                 *is_valid_position = is_valid_p;
196         return node;
197 }
198
199 #if 0
200 // Deprecated
201 // throws InvalidPositionException if not found
202 // TODO: Now this is deprecated, getNodeNoEx should be renamed
203 MapNode Map::getNode(v3s16 p)
204 {
205         v3s16 blockpos = getNodeBlockPos(p);
206         MapBlock *block = getBlockNoCreateNoEx(blockpos);
207         if (block == NULL)
208                 throw InvalidPositionException();
209         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
210         bool is_valid_position;
211         MapNode node = block->getNodeNoCheck(relpos, &is_valid_position);
212         if (!is_valid_position)
213                 throw InvalidPositionException();
214         return node;
215 }
216 #endif
217
218 // throws InvalidPositionException if not found
219 void Map::setNode(v3s16 p, MapNode & n)
220 {
221         v3s16 blockpos = getNodeBlockPos(p);
222         MapBlock *block = getBlockNoCreate(blockpos);
223         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
224         // Never allow placing CONTENT_IGNORE, it fucks up stuff
225         if(n.getContent() == CONTENT_IGNORE){
226                 bool temp_bool;
227                 errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
228                                 <<" while trying to replace \""
229                                 <<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos, &temp_bool)).name
230                                 <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
231                 debug_stacks_print_to(infostream);
232                 return;
233         }
234         block->setNodeNoCheck(relpos, n);
235 }
236
237
238 /*
239         Goes recursively through the neighbours of the node.
240
241         Alters only transparent nodes.
242
243         If the lighting of the neighbour is lower than the lighting of
244         the node was (before changing it to 0 at the step before), the
245         lighting of the neighbour is set to 0 and then the same stuff
246         repeats for the neighbour.
247
248         The ending nodes of the routine are stored in light_sources.
249         This is useful when a light is removed. In such case, this
250         routine can be called for the light node and then again for
251         light_sources to re-light the area without the removed light.
252
253         values of from_nodes are lighting values.
254 */
255 void Map::unspreadLight(enum LightBank bank,
256                 std::map<v3s16, u8> & from_nodes,
257                 std::set<v3s16> & light_sources,
258                 std::map<v3s16, MapBlock*>  & modified_blocks)
259 {
260         INodeDefManager *nodemgr = m_gamedef->ndef();
261
262         v3s16 dirs[6] = {
263                 v3s16(0,0,1), // back
264                 v3s16(0,1,0), // top
265                 v3s16(1,0,0), // right
266                 v3s16(0,0,-1), // front
267                 v3s16(0,-1,0), // bottom
268                 v3s16(-1,0,0), // left
269         };
270
271         if(from_nodes.empty())
272                 return;
273
274         u32 blockchangecount = 0;
275
276         std::map<v3s16, u8> unlighted_nodes;
277
278         /*
279                 Initialize block cache
280         */
281         v3s16 blockpos_last;
282         MapBlock *block = NULL;
283         // Cache this a bit, too
284         bool block_checked_in_modified = false;
285
286         for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
287                 j != from_nodes.end(); ++j)
288         {
289                 v3s16 pos = j->first;
290                 v3s16 blockpos = getNodeBlockPos(pos);
291
292                 // Only fetch a new block if the block position has changed
293                 try{
294                         if(block == NULL || blockpos != blockpos_last){
295                                 block = getBlockNoCreate(blockpos);
296                                 blockpos_last = blockpos;
297
298                                 block_checked_in_modified = false;
299                                 blockchangecount++;
300                         }
301                 }
302                 catch(InvalidPositionException &e)
303                 {
304                         continue;
305                 }
306
307                 if(block->isDummy())
308                         continue;
309
310                 // Calculate relative position in block
311                 //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
312
313                 // Get node straight from the block
314                 //MapNode n = block->getNode(relpos);
315
316                 u8 oldlight = j->second;
317
318                 // Loop through 6 neighbors
319                 for(u16 i=0; i<6; i++)
320                 {
321                         // Get the position of the neighbor node
322                         v3s16 n2pos = pos + dirs[i];
323
324                         // Get the block where the node is located
325                         v3s16 blockpos, relpos;
326                         getNodeBlockPosWithOffset(n2pos, blockpos, relpos);
327
328                         // Only fetch a new block if the block position has changed
329                         try {
330                                 if(block == NULL || blockpos != blockpos_last){
331                                         block = getBlockNoCreate(blockpos);
332                                         blockpos_last = blockpos;
333
334                                         block_checked_in_modified = false;
335                                         blockchangecount++;
336                                 }
337                         }
338                         catch(InvalidPositionException &e) {
339                                 continue;
340                         }
341
342                         // Get node straight from the block
343                         bool is_valid_position;
344                         MapNode n2 = block->getNode(relpos, &is_valid_position);
345                         if (!is_valid_position)
346                                 continue;
347
348                         bool changed = false;
349
350                         //TODO: Optimize output by optimizing light_sources?
351
352                         /*
353                                 If the neighbor is dimmer than what was specified
354                                 as oldlight (the light of the previous node)
355                         */
356                         if(n2.getLight(bank, nodemgr) < oldlight)
357                         {
358                                 /*
359                                         And the neighbor is transparent and it has some light
360                                 */
361                                 if(nodemgr->get(n2).light_propagates
362                                                 && n2.getLight(bank, nodemgr) != 0)
363                                 {
364                                         /*
365                                                 Set light to 0 and add to queue
366                                         */
367
368                                         u8 current_light = n2.getLight(bank, nodemgr);
369                                         n2.setLight(bank, 0, nodemgr);
370                                         block->setNode(relpos, n2);
371
372                                         unlighted_nodes[n2pos] = current_light;
373                                         changed = true;
374
375                                         /*
376                                                 Remove from light_sources if it is there
377                                                 NOTE: This doesn't happen nearly at all
378                                         */
379                                         /*if(light_sources.find(n2pos))
380                                         {
381                                                 infostream<<"Removed from light_sources"<<std::endl;
382                                                 light_sources.remove(n2pos);
383                                         }*/
384                                 }
385
386                                 /*// DEBUG
387                                 if(light_sources.find(n2pos) != NULL)
388                                         light_sources.remove(n2pos);*/
389                         }
390                         else{
391                                 light_sources.insert(n2pos);
392                         }
393
394                         // Add to modified_blocks
395                         if(changed == true && block_checked_in_modified == false)
396                         {
397                                 // If the block is not found in modified_blocks, add.
398                                 if(modified_blocks.find(blockpos) == modified_blocks.end())
399                                 {
400                                         modified_blocks[blockpos] = block;
401                                 }
402                                 block_checked_in_modified = true;
403                         }
404                 }
405         }
406
407         /*infostream<<"unspreadLight(): Changed block "
408         <<blockchangecount<<" times"
409         <<" for "<<from_nodes.size()<<" nodes"
410         <<std::endl;*/
411
412         if(!unlighted_nodes.empty())
413                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
414 }
415
416 /*
417         A single-node wrapper of the above
418 */
419 void Map::unLightNeighbors(enum LightBank bank,
420                 v3s16 pos, u8 lightwas,
421                 std::set<v3s16> & light_sources,
422                 std::map<v3s16, MapBlock*>  & modified_blocks)
423 {
424         std::map<v3s16, u8> from_nodes;
425         from_nodes[pos] = lightwas;
426
427         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
428 }
429
430 /*
431         Lights neighbors of from_nodes, collects all them and then
432         goes on recursively.
433 */
434 void Map::spreadLight(enum LightBank bank,
435                 std::set<v3s16> & from_nodes,
436                 std::map<v3s16, MapBlock*> & modified_blocks)
437 {
438         INodeDefManager *nodemgr = m_gamedef->ndef();
439
440         const v3s16 dirs[6] = {
441                 v3s16(0,0,1), // back
442                 v3s16(0,1,0), // top
443                 v3s16(1,0,0), // right
444                 v3s16(0,0,-1), // front
445                 v3s16(0,-1,0), // bottom
446                 v3s16(-1,0,0), // left
447         };
448
449         if(from_nodes.empty())
450                 return;
451
452         u32 blockchangecount = 0;
453
454         std::set<v3s16> lighted_nodes;
455
456         /*
457                 Initialize block cache
458         */
459         v3s16 blockpos_last;
460         MapBlock *block = NULL;
461                 // Cache this a bit, too
462         bool block_checked_in_modified = false;
463
464         for(std::set<v3s16>::iterator j = from_nodes.begin();
465                 j != from_nodes.end(); ++j)
466         {
467                 v3s16 pos = *j;
468                 v3s16 blockpos, relpos;
469
470                 getNodeBlockPosWithOffset(pos, blockpos, relpos);
471
472                 // Only fetch a new block if the block position has changed
473                 try {
474                         if(block == NULL || blockpos != blockpos_last){
475                                 block = getBlockNoCreate(blockpos);
476                                 blockpos_last = blockpos;
477
478                                 block_checked_in_modified = false;
479                                 blockchangecount++;
480                         }
481                 }
482                 catch(InvalidPositionException &e) {
483                         continue;
484                 }
485
486                 if(block->isDummy())
487                         continue;
488
489                 // Get node straight from the block
490                 bool is_valid_position;
491                 MapNode n = block->getNode(relpos, &is_valid_position);
492
493                 u8 oldlight = is_valid_position ? n.getLight(bank, nodemgr) : 0;
494                 u8 newlight = diminish_light(oldlight);
495
496                 // Loop through 6 neighbors
497                 for(u16 i=0; i<6; i++){
498                         // Get the position of the neighbor node
499                         v3s16 n2pos = pos + dirs[i];
500
501                         // Get the block where the node is located
502                         v3s16 blockpos, relpos;
503                         getNodeBlockPosWithOffset(n2pos, blockpos, relpos);
504
505                         // Only fetch a new block if the block position has changed
506                         try {
507                                 if(block == NULL || blockpos != blockpos_last){
508                                         block = getBlockNoCreate(blockpos);
509                                         blockpos_last = blockpos;
510
511                                         block_checked_in_modified = false;
512                                         blockchangecount++;
513                                 }
514                         }
515                         catch(InvalidPositionException &e) {
516                                 continue;
517                         }
518
519                         // Get node straight from the block
520                         MapNode n2 = block->getNode(relpos, &is_valid_position);
521                         if (!is_valid_position)
522                                 continue;
523
524                         bool changed = false;
525                         /*
526                                 If the neighbor is brighter than the current node,
527                                 add to list (it will light up this node on its turn)
528                         */
529                         if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
530                         {
531                                 lighted_nodes.insert(n2pos);
532                                 changed = true;
533                         }
534                         /*
535                                 If the neighbor is dimmer than how much light this node
536                                 would spread on it, add to list
537                         */
538                         if(n2.getLight(bank, nodemgr) < newlight)
539                         {
540                                 if(nodemgr->get(n2).light_propagates)
541                                 {
542                                         n2.setLight(bank, newlight, nodemgr);
543                                         block->setNode(relpos, n2);
544                                         lighted_nodes.insert(n2pos);
545                                         changed = true;
546                                 }
547                         }
548
549                         // Add to modified_blocks
550                         if(changed == true && block_checked_in_modified == false)
551                         {
552                                 // If the block is not found in modified_blocks, add.
553                                 if(modified_blocks.find(blockpos) == modified_blocks.end())
554                                 {
555                                         modified_blocks[blockpos] = block;
556                                 }
557                                 block_checked_in_modified = true;
558                         }
559                 }
560         }
561
562         /*infostream<<"spreadLight(): Changed block "
563                         <<blockchangecount<<" times"
564                         <<" for "<<from_nodes.size()<<" nodes"
565                         <<std::endl;*/
566
567         if(!lighted_nodes.empty())
568                 spreadLight(bank, lighted_nodes, modified_blocks);
569 }
570
571 /*
572         A single-node source variation of the above.
573 */
574 void Map::lightNeighbors(enum LightBank bank,
575                 v3s16 pos,
576                 std::map<v3s16, MapBlock*> & modified_blocks)
577 {
578         std::set<v3s16> from_nodes;
579         from_nodes.insert(pos);
580         spreadLight(bank, from_nodes, modified_blocks);
581 }
582
583 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
584 {
585         INodeDefManager *nodemgr = m_gamedef->ndef();
586
587         v3s16 dirs[6] = {
588                 v3s16(0,0,1), // back
589                 v3s16(0,1,0), // top
590                 v3s16(1,0,0), // right
591                 v3s16(0,0,-1), // front
592                 v3s16(0,-1,0), // bottom
593                 v3s16(-1,0,0), // left
594         };
595
596         u8 brightest_light = 0;
597         v3s16 brightest_pos(0,0,0);
598         bool found_something = false;
599
600         // Loop through 6 neighbors
601         for(u16 i=0; i<6; i++){
602                 // Get the position of the neighbor node
603                 v3s16 n2pos = p + dirs[i];
604                 MapNode n2;
605                 bool is_valid_position;
606                 n2 = getNodeNoEx(n2pos, &is_valid_position);
607                 if (!is_valid_position)
608                         continue;
609
610                 if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){
611                         brightest_light = n2.getLight(bank, nodemgr);
612                         brightest_pos = n2pos;
613                         found_something = true;
614                 }
615         }
616
617         if(found_something == false)
618                 throw InvalidPositionException();
619
620         return brightest_pos;
621 }
622
623 /*
624         Propagates sunlight down from a node.
625         Starting point gets sunlight.
626
627         Returns the lowest y value of where the sunlight went.
628
629         Mud is turned into grass in where the sunlight stops.
630 */
631 s16 Map::propagateSunlight(v3s16 start,
632                 std::map<v3s16, MapBlock*> & modified_blocks)
633 {
634         INodeDefManager *nodemgr = m_gamedef->ndef();
635
636         s16 y = start.Y;
637         for(; ; y--)
638         {
639                 v3s16 pos(start.X, y, start.Z);
640
641                 v3s16 blockpos = getNodeBlockPos(pos);
642                 MapBlock *block;
643                 try{
644                         block = getBlockNoCreate(blockpos);
645                 }
646                 catch(InvalidPositionException &e)
647                 {
648                         break;
649                 }
650
651                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
652                 bool is_valid_position;
653                 MapNode n = block->getNode(relpos, &is_valid_position);
654                 if (!is_valid_position)
655                         break;
656
657                 if(nodemgr->get(n).sunlight_propagates)
658                 {
659                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
660                         block->setNode(relpos, n);
661
662                         modified_blocks[blockpos] = block;
663                 }
664                 else
665                 {
666                         // Sunlight goes no further
667                         break;
668                 }
669         }
670         return y + 1;
671 }
672
673 void Map::updateLighting(enum LightBank bank,
674                 std::map<v3s16, MapBlock*> & a_blocks,
675                 std::map<v3s16, MapBlock*> & modified_blocks)
676 {
677         INodeDefManager *nodemgr = m_gamedef->ndef();
678
679         /*m_dout<<"Map::updateLighting(): "
680                         <<a_blocks.size()<<" blocks."<<std::endl;*/
681
682         //TimeTaker timer("updateLighting");
683
684         // For debugging
685         //bool debug=true;
686         //u32 count_was = modified_blocks.size();
687
688         //std::map<v3s16, MapBlock*> blocks_to_update;
689
690         std::set<v3s16> light_sources;
691
692         std::map<v3s16, u8> unlight_from;
693
694         int num_bottom_invalid = 0;
695
696         {
697         //TimeTaker t("first stuff");
698
699         for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
700                 i != a_blocks.end(); ++i)
701         {
702                 MapBlock *block = i->second;
703
704                 for(;;)
705                 {
706                         // Don't bother with dummy blocks.
707                         if(block->isDummy())
708                                 break;
709
710                         v3s16 pos = block->getPos();
711                         v3s16 posnodes = block->getPosRelative();
712                         modified_blocks[pos] = block;
713                         //blocks_to_update[pos] = block;
714
715                         /*
716                                 Clear all light from block
717                         */
718                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
719                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
720                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
721                         {
722                                 v3s16 p(x,y,z);
723                                 bool is_valid_position;
724                                 MapNode n = block->getNode(p, &is_valid_position);
725                                 if (!is_valid_position) {
726                                         /* This would happen when dealing with a
727                                            dummy block.
728                                         */
729                                         infostream<<"updateLighting(): InvalidPositionException"
730                                                         <<std::endl;
731                                         continue;
732                                 }
733                                 u8 oldlight = n.getLight(bank, nodemgr);
734                                 n.setLight(bank, 0, nodemgr);
735                                 block->setNode(p, n);
736
737                                 // If node sources light, add to list
738                                 u8 source = nodemgr->get(n).light_source;
739                                 if(source != 0)
740                                         light_sources.insert(p + posnodes);
741
742                                 // Collect borders for unlighting
743                                 if((x==0 || x == MAP_BLOCKSIZE-1
744                                                 || y==0 || y == MAP_BLOCKSIZE-1
745                                                 || z==0 || z == MAP_BLOCKSIZE-1)
746                                                 && oldlight != 0)
747                                 {
748                                         v3s16 p_map = p + posnodes;
749                                         unlight_from[p_map] = oldlight;
750                                 }
751
752
753                         }
754
755                         if(bank == LIGHTBANK_DAY)
756                         {
757                                 bool bottom_valid = block->propagateSunlight(light_sources);
758
759                                 if(!bottom_valid)
760                                         num_bottom_invalid++;
761
762                                 // If bottom is valid, we're done.
763                                 if(bottom_valid)
764                                         break;
765                         }
766                         else if(bank == LIGHTBANK_NIGHT)
767                         {
768                                 // For night lighting, sunlight is not propagated
769                                 break;
770                         }
771                         else
772                         {
773                                 assert("Invalid lighting bank" == NULL);
774                         }
775
776                         /*infostream<<"Bottom for sunlight-propagated block ("
777                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
778                                         <<std::endl;*/
779
780                         // Bottom sunlight is not valid; get the block and loop to it
781
782                         pos.Y--;
783                         try{
784                                 block = getBlockNoCreate(pos);
785                         }
786                         catch(InvalidPositionException &e)
787                         {
788                                 FATAL_ERROR("Invalid position");
789                         }
790
791                 }
792         }
793
794         }
795
796         /*
797                 Enable this to disable proper lighting for speeding up map
798                 generation for testing or whatever
799         */
800 #if 0
801         //if(g_settings->get(""))
802         {
803                 core::map<v3s16, MapBlock*>::Iterator i;
804                 i = blocks_to_update.getIterator();
805                 for(; i.atEnd() == false; i++)
806                 {
807                         MapBlock *block = i.getNode()->getValue();
808                         v3s16 p = block->getPos();
809                         block->setLightingExpired(false);
810                 }
811                 return;
812         }
813 #endif
814
815 #if 1
816         {
817                 //TimeTaker timer("unspreadLight");
818                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
819         }
820
821         /*if(debug)
822         {
823                 u32 diff = modified_blocks.size() - count_was;
824                 count_was = modified_blocks.size();
825                 infostream<<"unspreadLight modified "<<diff<<std::endl;
826         }*/
827
828         {
829                 //TimeTaker timer("spreadLight");
830                 spreadLight(bank, light_sources, modified_blocks);
831         }
832
833         /*if(debug)
834         {
835                 u32 diff = modified_blocks.size() - count_was;
836                 count_was = modified_blocks.size();
837                 infostream<<"spreadLight modified "<<diff<<std::endl;
838         }*/
839 #endif
840
841 #if 0
842         {
843                 //MapVoxelManipulator vmanip(this);
844
845                 // Make a manual voxel manipulator and load all the blocks
846                 // that touch the requested blocks
847                 ManualMapVoxelManipulator vmanip(this);
848
849                 {
850                 //TimeTaker timer("initialEmerge");
851
852                 core::map<v3s16, MapBlock*>::Iterator i;
853                 i = blocks_to_update.getIterator();
854                 for(; i.atEnd() == false; i++)
855                 {
856                         MapBlock *block = i.getNode()->getValue();
857                         v3s16 p = block->getPos();
858
859                         // Add all surrounding blocks
860                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
861
862                         /*
863                                 Add all surrounding blocks that have up-to-date lighting
864                                 NOTE: This doesn't quite do the job (not everything
865                                           appropriate is lighted)
866                         */
867                         /*for(s16 z=-1; z<=1; z++)
868                         for(s16 y=-1; y<=1; y++)
869                         for(s16 x=-1; x<=1; x++)
870                         {
871                                 v3s16 p2 = p + v3s16(x,y,z);
872                                 MapBlock *block = getBlockNoCreateNoEx(p2);
873                                 if(block == NULL)
874                                         continue;
875                                 if(block->isDummy())
876                                         continue;
877                                 if(block->getLightingExpired())
878                                         continue;
879                                 vmanip.initialEmerge(p2, p2);
880                         }*/
881
882                         // Lighting of block will be updated completely
883                         block->setLightingExpired(false);
884                 }
885                 }
886
887                 {
888                         //TimeTaker timer("unSpreadLight");
889                         vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
890                 }
891                 {
892                         //TimeTaker timer("spreadLight");
893                         vmanip.spreadLight(bank, light_sources, nodemgr);
894                 }
895                 {
896                         //TimeTaker timer("blitBack");
897                         vmanip.blitBack(modified_blocks);
898                 }
899                 /*infostream<<"emerge_time="<<emerge_time<<std::endl;
900                 emerge_time = 0;*/
901         }
902 #endif
903
904         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
905 }
906
907 void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
908                 std::map<v3s16, MapBlock*> & modified_blocks)
909 {
910         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
911         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
912
913         /*
914                 Update information about whether day and night light differ
915         */
916         for(std::map<v3s16, MapBlock*>::iterator
917                         i = modified_blocks.begin();
918                         i != modified_blocks.end(); ++i)
919         {
920                 MapBlock *block = i->second;
921                 block->expireDayNightDiff();
922         }
923 }
924
925 /*
926 */
927 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
928                 std::map<v3s16, MapBlock*> &modified_blocks,
929                 bool remove_metadata)
930 {
931         INodeDefManager *ndef = m_gamedef->ndef();
932
933         /*PrintInfo(m_dout);
934         m_dout<<"Map::addNodeAndUpdate(): p=("
935                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
936
937         /*
938                 From this node to nodes underneath:
939                 If lighting is sunlight (1.0), unlight neighbours and
940                 set lighting to 0.
941                 Else discontinue.
942         */
943
944         v3s16 toppos = p + v3s16(0,1,0);
945         //v3s16 bottompos = p + v3s16(0,-1,0);
946
947         bool node_under_sunlight = true;
948         std::set<v3s16> light_sources;
949
950         /*
951                 Collect old node for rollback
952         */
953         RollbackNode rollback_oldnode(this, p, m_gamedef);
954
955         /*
956                 If there is a node at top and it doesn't have sunlight,
957                 there has not been any sunlight going down.
958
959                 Otherwise there probably is.
960         */
961
962         bool is_valid_position;
963         MapNode topnode = getNodeNoEx(toppos, &is_valid_position);
964
965         if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
966                 node_under_sunlight = false;
967
968         /*
969                 Remove all light that has come out of this node
970         */
971
972         enum LightBank banks[] =
973         {
974                 LIGHTBANK_DAY,
975                 LIGHTBANK_NIGHT
976         };
977         for(s32 i=0; i<2; i++)
978         {
979                 enum LightBank bank = banks[i];
980
981                 u8 lightwas = getNodeNoEx(p).getLight(bank, ndef);
982
983                 // Add the block of the added node to modified_blocks
984                 v3s16 blockpos = getNodeBlockPos(p);
985                 MapBlock * block = getBlockNoCreate(blockpos);
986                 assert(block != NULL);
987                 modified_blocks[blockpos] = block;
988
989                 assert(isValidPosition(p));
990
991                 // Unlight neighbours of node.
992                 // This means setting light of all consequent dimmer nodes
993                 // to 0.
994                 // This also collects the nodes at the border which will spread
995                 // light again into this.
996                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
997
998                 n.setLight(bank, 0, ndef);
999         }
1000
1001         /*
1002                 If node lets sunlight through and is under sunlight, it has
1003                 sunlight too.
1004         */
1005         if(node_under_sunlight && ndef->get(n).sunlight_propagates)
1006         {
1007                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN, ndef);
1008         }
1009
1010         /*
1011                 Remove node metadata
1012         */
1013         if (remove_metadata) {
1014                 removeNodeMetadata(p);
1015         }
1016
1017         /*
1018                 Set the node on the map
1019         */
1020
1021         setNode(p, n);
1022
1023         /*
1024                 If node is under sunlight and doesn't let sunlight through,
1025                 take all sunlighted nodes under it and clear light from them
1026                 and from where the light has been spread.
1027                 TODO: This could be optimized by mass-unlighting instead
1028                           of looping
1029         */
1030         if(node_under_sunlight && !ndef->get(n).sunlight_propagates)
1031         {
1032                 s16 y = p.Y - 1;
1033                 for(;; y--){
1034                         //m_dout<<"y="<<y<<std::endl;
1035                         v3s16 n2pos(p.X, y, p.Z);
1036
1037                         MapNode n2;
1038
1039                         n2 = getNodeNoEx(n2pos, &is_valid_position);
1040                         if (!is_valid_position)
1041                                 break;
1042
1043                         if(n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
1044                         {
1045                                 unLightNeighbors(LIGHTBANK_DAY,
1046                                                 n2pos, n2.getLight(LIGHTBANK_DAY, ndef),
1047                                                 light_sources, modified_blocks);
1048                                 n2.setLight(LIGHTBANK_DAY, 0, ndef);
1049                                 setNode(n2pos, n2);
1050                         }
1051                         else
1052                                 break;
1053                 }
1054         }
1055
1056         for(s32 i=0; i<2; i++)
1057         {
1058                 enum LightBank bank = banks[i];
1059
1060                 /*
1061                         Spread light from all nodes that might be capable of doing so
1062                 */
1063                 spreadLight(bank, light_sources, modified_blocks);
1064         }
1065
1066         /*
1067                 Update information about whether day and night light differ
1068         */
1069         for(std::map<v3s16, MapBlock*>::iterator
1070                         i = modified_blocks.begin();
1071                         i != modified_blocks.end(); ++i)
1072         {
1073                 i->second->expireDayNightDiff();
1074         }
1075
1076         /*
1077                 Report for rollback
1078         */
1079         if(m_gamedef->rollback())
1080         {
1081                 RollbackNode rollback_newnode(this, p, m_gamedef);
1082                 RollbackAction action;
1083                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
1084                 m_gamedef->rollback()->reportAction(action);
1085         }
1086
1087         /*
1088                 Add neighboring liquid nodes and the node itself if it is
1089                 liquid (=water node was added) to transform queue.
1090         */
1091         v3s16 dirs[7] = {
1092                 v3s16(0,0,0), // self
1093                 v3s16(0,0,1), // back
1094                 v3s16(0,1,0), // top
1095                 v3s16(1,0,0), // right
1096                 v3s16(0,0,-1), // front
1097                 v3s16(0,-1,0), // bottom
1098                 v3s16(-1,0,0), // left
1099         };
1100         for(u16 i=0; i<7; i++)
1101         {
1102                 v3s16 p2 = p + dirs[i];
1103
1104                 MapNode n2 = getNodeNoEx(p2, &is_valid_position);
1105                 if(is_valid_position
1106                                 && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR))
1107                 {
1108                         m_transforming_liquid.push_back(p2);
1109                 }
1110         }
1111 }
1112
1113 /*
1114 */
1115 void Map::removeNodeAndUpdate(v3s16 p,
1116                 std::map<v3s16, MapBlock*> &modified_blocks)
1117 {
1118         INodeDefManager *ndef = m_gamedef->ndef();
1119
1120         /*PrintInfo(m_dout);
1121         m_dout<<"Map::removeNodeAndUpdate(): p=("
1122                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1123
1124         bool node_under_sunlight = true;
1125
1126         v3s16 toppos = p + v3s16(0,1,0);
1127
1128         // Node will be replaced with this
1129         content_t replace_material = CONTENT_AIR;
1130
1131         /*
1132                 Collect old node for rollback
1133         */
1134         RollbackNode rollback_oldnode(this, p, m_gamedef);
1135
1136         /*
1137                 If there is a node at top and it doesn't have sunlight,
1138                 there will be no sunlight going down.
1139         */
1140         bool is_valid_position;
1141         MapNode topnode = getNodeNoEx(toppos, &is_valid_position);
1142
1143         if(is_valid_position && topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
1144                 node_under_sunlight = false;
1145
1146         std::set<v3s16> light_sources;
1147
1148         enum LightBank banks[] =
1149         {
1150                 LIGHTBANK_DAY,
1151                 LIGHTBANK_NIGHT
1152         };
1153         for(s32 i=0; i<2; i++)
1154         {
1155                 enum LightBank bank = banks[i];
1156
1157                 /*
1158                         Unlight neighbors (in case the node is a light source)
1159                 */
1160                 unLightNeighbors(bank, p,
1161                                 getNodeNoEx(p).getLight(bank, ndef),
1162                                 light_sources, modified_blocks);
1163         }
1164
1165         /*
1166                 Remove node metadata
1167         */
1168
1169         removeNodeMetadata(p);
1170
1171         /*
1172                 Remove the node.
1173                 This also clears the lighting.
1174         */
1175
1176         MapNode n(replace_material);
1177         setNode(p, n);
1178
1179         for(s32 i=0; i<2; i++)
1180         {
1181                 enum LightBank bank = banks[i];
1182
1183                 /*
1184                         Recalculate lighting
1185                 */
1186                 spreadLight(bank, light_sources, modified_blocks);
1187         }
1188
1189         // Add the block of the removed node to modified_blocks
1190         v3s16 blockpos = getNodeBlockPos(p);
1191         MapBlock * block = getBlockNoCreate(blockpos);
1192         assert(block != NULL);
1193         modified_blocks[blockpos] = block;
1194
1195         /*
1196                 If the removed node was under sunlight, propagate the
1197                 sunlight down from it and then light all neighbors
1198                 of the propagated blocks.
1199         */
1200         if(node_under_sunlight)
1201         {
1202                 s16 ybottom = propagateSunlight(p, modified_blocks);
1203                 /*m_dout<<"Node was under sunlight. "
1204                                 "Propagating sunlight";
1205                 m_dout<<" -> ybottom="<<ybottom<<std::endl;*/
1206                 s16 y = p.Y;
1207                 for(; y >= ybottom; y--)
1208                 {
1209                         v3s16 p2(p.X, y, p.Z);
1210                         /*m_dout<<"lighting neighbors of node ("
1211                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1212                                         <<std::endl;*/
1213                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1214                 }
1215         }
1216         else
1217         {
1218                 // Set the lighting of this node to 0
1219                 // TODO: Is this needed? Lighting is cleared up there already.
1220                 MapNode n = getNodeNoEx(p, &is_valid_position);
1221                 if (is_valid_position) {
1222                         n.setLight(LIGHTBANK_DAY, 0, ndef);
1223                         setNode(p, n);
1224                 } else {
1225                         FATAL_ERROR("Invalid position");
1226                 }
1227         }
1228
1229         for(s32 i=0; i<2; i++)
1230         {
1231                 enum LightBank bank = banks[i];
1232
1233                 // Get the brightest neighbour node and propagate light from it
1234                 v3s16 n2p = getBrightestNeighbour(bank, p);
1235                 try{
1236                         //MapNode n2 = getNode(n2p);
1237                         lightNeighbors(bank, n2p, modified_blocks);
1238                 }
1239                 catch(InvalidPositionException &e)
1240                 {
1241                 }
1242         }
1243
1244         /*
1245                 Update information about whether day and night light differ
1246         */
1247         for(std::map<v3s16, MapBlock*>::iterator
1248                         i = modified_blocks.begin();
1249                         i != modified_blocks.end(); ++i)
1250         {
1251                 i->second->expireDayNightDiff();
1252         }
1253
1254         /*
1255                 Report for rollback
1256         */
1257         if(m_gamedef->rollback())
1258         {
1259                 RollbackNode rollback_newnode(this, p, m_gamedef);
1260                 RollbackAction action;
1261                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
1262                 m_gamedef->rollback()->reportAction(action);
1263         }
1264
1265         /*
1266                 Add neighboring liquid nodes and this node to transform queue.
1267                 (it's vital for the node itself to get updated last.)
1268         */
1269         v3s16 dirs[7] = {
1270                 v3s16(0,0,1), // back
1271                 v3s16(0,1,0), // top
1272                 v3s16(1,0,0), // right
1273                 v3s16(0,0,-1), // front
1274                 v3s16(0,-1,0), // bottom
1275                 v3s16(-1,0,0), // left
1276                 v3s16(0,0,0), // self
1277         };
1278         for(u16 i=0; i<7; i++)
1279         {
1280                 v3s16 p2 = p + dirs[i];
1281
1282                 bool is_position_valid;
1283                 MapNode n2 = getNodeNoEx(p2, &is_position_valid);
1284                 if (is_position_valid
1285                                 && (ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR))
1286                 {
1287                         m_transforming_liquid.push_back(p2);
1288                 }
1289         }
1290 }
1291
1292 bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
1293 {
1294         MapEditEvent event;
1295         event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
1296         event.p = p;
1297         event.n = n;
1298
1299         bool succeeded = true;
1300         try{
1301                 std::map<v3s16, MapBlock*> modified_blocks;
1302                 addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
1303
1304                 // Copy modified_blocks to event
1305                 for(std::map<v3s16, MapBlock*>::iterator
1306                                 i = modified_blocks.begin();
1307                                 i != modified_blocks.end(); ++i)
1308                 {
1309                         event.modified_blocks.insert(i->first);
1310                 }
1311         }
1312         catch(InvalidPositionException &e){
1313                 succeeded = false;
1314         }
1315
1316         dispatchEvent(&event);
1317
1318         return succeeded;
1319 }
1320
1321 bool Map::removeNodeWithEvent(v3s16 p)
1322 {
1323         MapEditEvent event;
1324         event.type = MEET_REMOVENODE;
1325         event.p = p;
1326
1327         bool succeeded = true;
1328         try{
1329                 std::map<v3s16, MapBlock*> modified_blocks;
1330                 removeNodeAndUpdate(p, modified_blocks);
1331
1332                 // Copy modified_blocks to event
1333                 for(std::map<v3s16, MapBlock*>::iterator
1334                                 i = modified_blocks.begin();
1335                                 i != modified_blocks.end(); ++i)
1336                 {
1337                         event.modified_blocks.insert(i->first);
1338                 }
1339         }
1340         catch(InvalidPositionException &e){
1341                 succeeded = false;
1342         }
1343
1344         dispatchEvent(&event);
1345
1346         return succeeded;
1347 }
1348
1349 bool Map::getDayNightDiff(v3s16 blockpos)
1350 {
1351         try{
1352                 v3s16 p = blockpos + v3s16(0,0,0);
1353                 MapBlock *b = getBlockNoCreate(p);
1354                 if(b->getDayNightDiff())
1355                         return true;
1356         }
1357         catch(InvalidPositionException &e){}
1358         // Leading edges
1359         try{
1360                 v3s16 p = blockpos + v3s16(-1,0,0);
1361                 MapBlock *b = getBlockNoCreate(p);
1362                 if(b->getDayNightDiff())
1363                         return true;
1364         }
1365         catch(InvalidPositionException &e){}
1366         try{
1367                 v3s16 p = blockpos + v3s16(0,-1,0);
1368                 MapBlock *b = getBlockNoCreate(p);
1369                 if(b->getDayNightDiff())
1370                         return true;
1371         }
1372         catch(InvalidPositionException &e){}
1373         try{
1374                 v3s16 p = blockpos + v3s16(0,0,-1);
1375                 MapBlock *b = getBlockNoCreate(p);
1376                 if(b->getDayNightDiff())
1377                         return true;
1378         }
1379         catch(InvalidPositionException &e){}
1380         // Trailing edges
1381         try{
1382                 v3s16 p = blockpos + v3s16(1,0,0);
1383                 MapBlock *b = getBlockNoCreate(p);
1384                 if(b->getDayNightDiff())
1385                         return true;
1386         }
1387         catch(InvalidPositionException &e){}
1388         try{
1389                 v3s16 p = blockpos + v3s16(0,1,0);
1390                 MapBlock *b = getBlockNoCreate(p);
1391                 if(b->getDayNightDiff())
1392                         return true;
1393         }
1394         catch(InvalidPositionException &e){}
1395         try{
1396                 v3s16 p = blockpos + v3s16(0,0,1);
1397                 MapBlock *b = getBlockNoCreate(p);
1398                 if(b->getDayNightDiff())
1399                         return true;
1400         }
1401         catch(InvalidPositionException &e){}
1402
1403         return false;
1404 }
1405
1406 struct TimeOrderedMapBlock {
1407         MapSector *sect;
1408         MapBlock *block;
1409
1410         TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
1411                 sect(sect),
1412                 block(block)
1413         {}
1414
1415         bool operator<(const TimeOrderedMapBlock &b) const
1416         {
1417                 return block->getUsageTimer() < b.block->getUsageTimer();
1418         };
1419 };
1420
1421 /*
1422         Updates usage timers
1423 */
1424 void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
1425                 std::vector<v3s16> *unloaded_blocks)
1426 {
1427         bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
1428
1429         // Profile modified reasons
1430         Profiler modprofiler;
1431
1432         std::vector<v2s16> sector_deletion_queue;
1433         u32 deleted_blocks_count = 0;
1434         u32 saved_blocks_count = 0;
1435         u32 block_count_all = 0;
1436
1437         beginSave();
1438
1439         // If there is no practical limit, we spare creation of mapblock_queue
1440         if (max_loaded_blocks == U32_MAX) {
1441                 for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1442                                 si != m_sectors.end(); ++si) {
1443                         MapSector *sector = si->second;
1444
1445                         bool all_blocks_deleted = true;
1446
1447                         MapBlockVect blocks;
1448                         sector->getBlocks(blocks);
1449
1450                         for (MapBlockVect::iterator i = blocks.begin();
1451                                         i != blocks.end(); ++i) {
1452                                 MapBlock *block = (*i);
1453
1454                                 block->incrementUsageTimer(dtime);
1455
1456                                 if (block->refGet() == 0
1457                                                 && block->getUsageTimer() > unload_timeout) {
1458                                         v3s16 p = block->getPos();
1459
1460                                         // Save if modified
1461                                         if (block->getModified() != MOD_STATE_CLEAN
1462                                                         && save_before_unloading) {
1463                                                 modprofiler.add(block->getModifiedReasonString(), 1);
1464                                                 if (!saveBlock(block))
1465                                                         continue;
1466                                                 saved_blocks_count++;
1467                                         }
1468
1469                                         // Delete from memory
1470                                         sector->deleteBlock(block);
1471
1472                                         if (unloaded_blocks)
1473                                                 unloaded_blocks->push_back(p);
1474
1475                                         deleted_blocks_count++;
1476                                 } else {
1477                                         all_blocks_deleted = false;
1478                                         block_count_all++;
1479                                 }
1480                         }
1481
1482                         if (all_blocks_deleted) {
1483                                 sector_deletion_queue.push_back(si->first);
1484                         }
1485                 }
1486         } else {
1487                 std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
1488                 for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1489                                 si != m_sectors.end(); ++si) {
1490                         MapSector *sector = si->second;
1491
1492                         MapBlockVect blocks;
1493                         sector->getBlocks(blocks);
1494
1495                         for(MapBlockVect::iterator i = blocks.begin();
1496                                         i != blocks.end(); ++i) {
1497                                 MapBlock *block = (*i);
1498
1499                                 block->incrementUsageTimer(dtime);
1500                                 mapblock_queue.push(TimeOrderedMapBlock(sector, block));
1501                         }
1502                 }
1503                 block_count_all = mapblock_queue.size();
1504                 // Delete old blocks, and blocks over the limit from the memory
1505                 while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks
1506                                 || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
1507                         TimeOrderedMapBlock b = mapblock_queue.top();
1508                         mapblock_queue.pop();
1509
1510                         MapBlock *block = b.block;
1511
1512                         if (block->refGet() != 0)
1513                                 continue;
1514
1515                         v3s16 p = block->getPos();
1516
1517                         // Save if modified
1518                         if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
1519                                 modprofiler.add(block->getModifiedReasonString(), 1);
1520                                 if (!saveBlock(block))
1521                                         continue;
1522                                 saved_blocks_count++;
1523                         }
1524
1525                         // Delete from memory
1526                         b.sect->deleteBlock(block);
1527
1528                         if (unloaded_blocks)
1529                                 unloaded_blocks->push_back(p);
1530
1531                         deleted_blocks_count++;
1532                         block_count_all--;
1533                 }
1534                 // Delete empty sectors
1535                 for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1536                         si != m_sectors.end(); ++si) {
1537                         if (si->second->empty()) {
1538                                 sector_deletion_queue.push_back(si->first);
1539                         }
1540                 }
1541         }
1542         endSave();
1543
1544         // Finally delete the empty sectors
1545         deleteSectors(sector_deletion_queue);
1546
1547         if(deleted_blocks_count != 0)
1548         {
1549                 PrintInfo(infostream); // ServerMap/ClientMap:
1550                 infostream<<"Unloaded "<<deleted_blocks_count
1551                                 <<" blocks from memory";
1552                 if(save_before_unloading)
1553                         infostream<<", of which "<<saved_blocks_count<<" were written";
1554                 infostream<<", "<<block_count_all<<" blocks in memory";
1555                 infostream<<"."<<std::endl;
1556                 if(saved_blocks_count != 0){
1557                         PrintInfo(infostream); // ServerMap/ClientMap:
1558                         infostream<<"Blocks modified by: "<<std::endl;
1559                         modprofiler.print(infostream);
1560                 }
1561         }
1562 }
1563
1564 void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
1565 {
1566         timerUpdate(0.0, -1.0, 0, unloaded_blocks);
1567 }
1568
1569 void Map::deleteSectors(std::vector<v2s16> &sectorList)
1570 {
1571         for(std::vector<v2s16>::iterator j = sectorList.begin();
1572                 j != sectorList.end(); ++j) {
1573                 MapSector *sector = m_sectors[*j];
1574                 // If sector is in sector cache, remove it from there
1575                 if(m_sector_cache == sector)
1576                         m_sector_cache = NULL;
1577                 // Remove from map and delete
1578                 m_sectors.erase(*j);
1579                 delete sector;
1580         }
1581 }
1582
1583 void Map::PrintInfo(std::ostream &out)
1584 {
1585         out<<"Map: ";
1586 }
1587
1588 #define WATER_DROP_BOOST 4
1589
1590 enum NeighborType {
1591         NEIGHBOR_UPPER,
1592         NEIGHBOR_SAME_LEVEL,
1593         NEIGHBOR_LOWER
1594 };
1595 struct NodeNeighbor {
1596         MapNode n;
1597         NeighborType t;
1598         v3s16 p;
1599         bool l; //can liquid
1600
1601         NodeNeighbor()
1602                 : n(CONTENT_AIR)
1603         { }
1604
1605         NodeNeighbor(const MapNode &node, NeighborType n_type, v3s16 pos)
1606                 : n(node),
1607                   t(n_type),
1608                   p(pos)
1609         { }
1610 };
1611
1612 void Map::transforming_liquid_add(v3s16 p) {
1613         m_transforming_liquid.push_back(p);
1614 }
1615
1616 s32 Map::transforming_liquid_size() {
1617         return m_transforming_liquid.size();
1618 }
1619
1620 void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
1621 {
1622
1623         INodeDefManager *nodemgr = m_gamedef->ndef();
1624
1625         DSTACK(FUNCTION_NAME);
1626         //TimeTaker timer("transformLiquids()");
1627
1628         u32 loopcount = 0;
1629         u32 initial_size = m_transforming_liquid.size();
1630
1631         /*if(initial_size != 0)
1632                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1633
1634         // list of nodes that due to viscosity have not reached their max level height
1635         std::deque<v3s16> must_reflow;
1636
1637         // List of MapBlocks that will require a lighting update (due to lava)
1638         std::map<v3s16, MapBlock *> lighting_modified_blocks;
1639
1640         u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
1641         u32 loop_max = liquid_loop_max;
1642
1643 #if 0
1644
1645         /* If liquid_loop_max is not keeping up with the queue size increase
1646          * loop_max up to a maximum of liquid_loop_max * dedicated_server_step.
1647          */
1648         if (m_transforming_liquid.size() > loop_max * 2) {
1649                 // "Burst" mode
1650                 float server_step = g_settings->getFloat("dedicated_server_step");
1651                 if (m_transforming_liquid_loop_count_multiplier - 1.0 < server_step)
1652                         m_transforming_liquid_loop_count_multiplier *= 1.0 + server_step / 10;
1653         } else {
1654                 m_transforming_liquid_loop_count_multiplier = 1.0;
1655         }
1656
1657         loop_max *= m_transforming_liquid_loop_count_multiplier;
1658 #endif
1659
1660         while (m_transforming_liquid.size() != 0)
1661         {
1662                 // This should be done here so that it is done when continue is used
1663                 if (loopcount >= initial_size || loopcount >= loop_max)
1664                         break;
1665                 loopcount++;
1666
1667                 /*
1668                         Get a queued transforming liquid node
1669                 */
1670                 v3s16 p0 = m_transforming_liquid.front();
1671                 m_transforming_liquid.pop_front();
1672
1673                 MapNode n0 = getNodeNoEx(p0);
1674
1675                 /*
1676                         Collect information about current node
1677                  */
1678                 s8 liquid_level = -1;
1679                 content_t liquid_kind = CONTENT_IGNORE;
1680                 content_t floodable_node = CONTENT_AIR;
1681                 const ContentFeatures &cf = nodemgr->get(n0);
1682                 LiquidType liquid_type = cf.liquid_type;
1683                 switch (liquid_type) {
1684                         case LIQUID_SOURCE:
1685                                 liquid_level = LIQUID_LEVEL_SOURCE;
1686                                 liquid_kind = nodemgr->getId(cf.liquid_alternative_flowing);
1687                                 break;
1688                         case LIQUID_FLOWING:
1689                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1690                                 liquid_kind = n0.getContent();
1691                                 break;
1692                         case LIQUID_NONE:
1693                                 // if this node is 'floodable', it *could* be transformed
1694                                 // into a liquid, otherwise, continue with the next node.
1695                                 if (!cf.floodable)
1696                                         continue;
1697                                 floodable_node = n0.getContent();
1698                                 liquid_kind = CONTENT_AIR;
1699                                 break;
1700                 }
1701
1702                 /*
1703                         Collect information about the environment
1704                  */
1705                 const v3s16 *dirs = g_6dirs;
1706                 NodeNeighbor sources[6]; // surrounding sources
1707                 int num_sources = 0;
1708                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1709                 int num_flows = 0;
1710                 NodeNeighbor airs[6]; // surrounding air
1711                 int num_airs = 0;
1712                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1713                 int num_neutrals = 0;
1714                 bool flowing_down = false;
1715                 for (u16 i = 0; i < 6; i++) {
1716                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1717                         switch (i) {
1718                                 case 1:
1719                                         nt = NEIGHBOR_UPPER;
1720                                         break;
1721                                 case 4:
1722                                         nt = NEIGHBOR_LOWER;
1723                                         break;
1724                         }
1725                         v3s16 npos = p0 + dirs[i];
1726                         NodeNeighbor nb(getNodeNoEx(npos), nt, npos);
1727                         const ContentFeatures &cfnb = nodemgr->get(nb.n);
1728                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1729                                 case LIQUID_NONE:
1730                                         if (cfnb.floodable) {
1731                                                 airs[num_airs++] = nb;
1732                                                 // if the current node is a water source the neighbor
1733                                                 // should be enqueded for transformation regardless of whether the
1734                                                 // current node changes or not.
1735                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1736                                                         m_transforming_liquid.push_back(npos);
1737                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1738                                                 if (nb.t == NEIGHBOR_LOWER)
1739                                                         flowing_down = true;
1740                                         } else {
1741                                                 neutrals[num_neutrals++] = nb;
1742                                                 // If neutral below is ignore prevent water spreading outwards
1743                                                 if (nb.t == NEIGHBOR_LOWER &&
1744                                                                 nb.n.getContent() == CONTENT_IGNORE)
1745                                                         flowing_down = true;
1746                                         }
1747                                         break;
1748                                 case LIQUID_SOURCE:
1749                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1750                                         if (liquid_kind == CONTENT_AIR)
1751                                                 liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
1752                                         if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
1753                                                 neutrals[num_neutrals++] = nb;
1754                                         } else {
1755                                                 // Do not count bottom source, it will screw things up
1756                                                 if(dirs[i].Y != -1)
1757                                                         sources[num_sources++] = nb;
1758                                         }
1759                                         break;
1760                                 case LIQUID_FLOWING:
1761                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1762                                         if (liquid_kind == CONTENT_AIR)
1763                                                 liquid_kind = nodemgr->getId(cfnb.liquid_alternative_flowing);
1764                                         if (nodemgr->getId(cfnb.liquid_alternative_flowing) != liquid_kind) {
1765                                                 neutrals[num_neutrals++] = nb;
1766                                         } else {
1767                                                 flows[num_flows++] = nb;
1768                                                 if (nb.t == NEIGHBOR_LOWER)
1769                                                         flowing_down = true;
1770                                         }
1771                                         break;
1772                         }
1773                 }
1774
1775                 /*
1776                         decide on the type (and possibly level) of the current node
1777                  */
1778                 content_t new_node_content;
1779                 s8 new_node_level = -1;
1780                 s8 max_node_level = -1;
1781
1782                 u8 range = nodemgr->get(liquid_kind).liquid_range;
1783                 if (range > LIQUID_LEVEL_MAX + 1)
1784                         range = LIQUID_LEVEL_MAX + 1;
1785
1786                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
1787                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1788                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1789                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1790                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1791                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
1792                         // liquid_kind is set properly, see above
1793                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1794                         if (new_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
1795                                 new_node_content = liquid_kind;
1796                         else
1797                                 new_node_content = floodable_node;
1798                 } else {
1799                         // no surrounding sources, so get the maximum level that can flow into this node
1800                         for (u16 i = 0; i < num_flows; i++) {
1801                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1802                                 switch (flows[i].t) {
1803                                         case NEIGHBOR_UPPER:
1804                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1805                                                         max_node_level = LIQUID_LEVEL_MAX;
1806                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1807                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1808                                                 } else if (nb_liquid_level > max_node_level) {
1809                                                         max_node_level = nb_liquid_level;
1810                                                 }
1811                                                 break;
1812                                         case NEIGHBOR_LOWER:
1813                                                 break;
1814                                         case NEIGHBOR_SAME_LEVEL:
1815                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1816                                                                 nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level)
1817                                                         max_node_level = nb_liquid_level - 1;
1818                                                 break;
1819                                 }
1820                         }
1821
1822                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1823                         if (viscosity > 1 && max_node_level != liquid_level) {
1824                                 // amount to gain, limited by viscosity
1825                                 // must be at least 1 in absolute value
1826                                 s8 level_inc = max_node_level - liquid_level;
1827                                 if (level_inc < -viscosity || level_inc > viscosity)
1828                                         new_node_level = liquid_level + level_inc/viscosity;
1829                                 else if (level_inc < 0)
1830                                         new_node_level = liquid_level - 1;
1831                                 else if (level_inc > 0)
1832                                         new_node_level = liquid_level + 1;
1833                                 if (new_node_level != max_node_level)
1834                                         must_reflow.push_back(p0);
1835                         } else {
1836                                 new_node_level = max_node_level;
1837                         }
1838
1839                         if (max_node_level >= (LIQUID_LEVEL_MAX + 1 - range))
1840                                 new_node_content = liquid_kind;
1841                         else
1842                                 new_node_content = floodable_node;
1843
1844                 }
1845
1846                 /*
1847                         check if anything has changed. if not, just continue with the next node.
1848                  */
1849                 if (new_node_content == n0.getContent() &&
1850                                 (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1851                                 ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1852                                 ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1853                                 == flowing_down)))
1854                         continue;
1855
1856
1857                 /*
1858                         update the current node
1859                  */
1860                 MapNode n00 = n0;
1861                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1862                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1863                         // set level to last 3 bits, flowing down bit to 4th bit
1864                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1865                 } else {
1866                         // set the liquid level and flow bit to 0
1867                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1868                 }
1869                 n0.setContent(new_node_content);
1870
1871                 // Find out whether there is a suspect for this action
1872                 std::string suspect;
1873                 if (m_gamedef->rollback())
1874                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1875
1876                 if (m_gamedef->rollback() && !suspect.empty()) {
1877                         // Blame suspect
1878                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1879                         // Get old node for rollback
1880                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
1881                         // Set node
1882                         setNode(p0, n0);
1883                         // Report
1884                         RollbackNode rollback_newnode(this, p0, m_gamedef);
1885                         RollbackAction action;
1886                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1887                         m_gamedef->rollback()->reportAction(action);
1888                 } else {
1889                         // Set node
1890                         setNode(p0, n0);
1891                 }
1892
1893                 v3s16 blockpos = getNodeBlockPos(p0);
1894                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1895                 if (block != NULL) {
1896                         modified_blocks[blockpos] =  block;
1897                         // If new or old node emits light, MapBlock requires lighting update
1898                         if (nodemgr->get(n0).light_source != 0 ||
1899                                         nodemgr->get(n00).light_source != 0)
1900                                 lighting_modified_blocks[block->getPos()] = block;
1901                 }
1902
1903                 /*
1904                         enqueue neighbors for update if neccessary
1905                  */
1906                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1907                         case LIQUID_SOURCE:
1908                         case LIQUID_FLOWING:
1909                                 // make sure source flows into all neighboring nodes
1910                                 for (u16 i = 0; i < num_flows; i++)
1911                                         if (flows[i].t != NEIGHBOR_UPPER)
1912                                                 m_transforming_liquid.push_back(flows[i].p);
1913                                 for (u16 i = 0; i < num_airs; i++)
1914                                         if (airs[i].t != NEIGHBOR_UPPER)
1915                                                 m_transforming_liquid.push_back(airs[i].p);
1916                                 break;
1917                         case LIQUID_NONE:
1918                                 // this flow has turned to air; neighboring flows might need to do the same
1919                                 for (u16 i = 0; i < num_flows; i++)
1920                                         m_transforming_liquid.push_back(flows[i].p);
1921                                 break;
1922                 }
1923         }
1924         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1925
1926         for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
1927                 m_transforming_liquid.push_back(*iter);
1928
1929         updateLighting(lighting_modified_blocks, modified_blocks);
1930
1931
1932         /* ----------------------------------------------------------------------
1933          * Manage the queue so that it does not grow indefinately
1934          */
1935         u16 time_until_purge = g_settings->getU16("liquid_queue_purge_time");
1936
1937         if (time_until_purge == 0)
1938                 return; // Feature disabled
1939
1940         time_until_purge *= 1000;       // seconds -> milliseconds
1941
1942         u32 curr_time = getTime(PRECISION_MILLI);
1943         u32 prev_unprocessed = m_unprocessed_count;
1944         m_unprocessed_count = m_transforming_liquid.size();
1945
1946         // if unprocessed block count is decreasing or stable
1947         if (m_unprocessed_count <= prev_unprocessed) {
1948                 m_queue_size_timer_started = false;
1949         } else {
1950                 if (!m_queue_size_timer_started)
1951                         m_inc_trending_up_start_time = curr_time;
1952                 m_queue_size_timer_started = true;
1953         }
1954
1955         // Account for curr_time overflowing
1956         if (m_queue_size_timer_started && m_inc_trending_up_start_time > curr_time)
1957                 m_queue_size_timer_started = false;
1958
1959         /* If the queue has been growing for more than liquid_queue_purge_time seconds
1960          * and the number of unprocessed blocks is still > liquid_loop_max then we
1961          * cannot keep up; dump the oldest blocks from the queue so that the queue
1962          * has liquid_loop_max items in it
1963          */
1964         if (m_queue_size_timer_started
1965                         && curr_time - m_inc_trending_up_start_time > time_until_purge
1966                         && m_unprocessed_count > liquid_loop_max) {
1967
1968                 size_t dump_qty = m_unprocessed_count - liquid_loop_max;
1969
1970                 infostream << "transformLiquids(): DUMPING " << dump_qty
1971                            << " blocks from the queue" << std::endl;
1972
1973                 while (dump_qty--)
1974                         m_transforming_liquid.pop_front();
1975
1976                 m_queue_size_timer_started = false; // optimistically assume we can keep up now
1977                 m_unprocessed_count = m_transforming_liquid.size();
1978         }
1979 }
1980
1981 std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
1982 {
1983         std::vector<v3s16> positions_with_meta;
1984
1985         sortBoxVerticies(p1, p2);
1986         v3s16 bpmin = getNodeBlockPos(p1);
1987         v3s16 bpmax = getNodeBlockPos(p2);
1988
1989         VoxelArea area(p1, p2);
1990
1991         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
1992         for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
1993         for (s16 x = bpmin.X; x <= bpmax.X; x++) {
1994                 v3s16 blockpos(x, y, z);
1995
1996                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1997                 if (!block) {
1998                         verbosestream << "Map::getNodeMetadata(): Need to emerge "
1999                                 << PP(blockpos) << std::endl;
2000                         block = emergeBlock(blockpos, false);
2001                 }
2002                 if (!block) {
2003                         infostream << "WARNING: Map::getNodeMetadata(): Block not found"
2004                                 << std::endl;
2005                         continue;
2006                 }
2007
2008                 v3s16 p_base = blockpos * MAP_BLOCKSIZE;
2009                 std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
2010                 for (size_t i = 0; i != keys.size(); i++) {
2011                         v3s16 p(keys[i] + p_base);
2012                         if (!area.contains(p))
2013                                 continue;
2014
2015                         positions_with_meta.push_back(p);
2016                 }
2017         }
2018
2019         return positions_with_meta;
2020 }
2021
2022 NodeMetadata *Map::getNodeMetadata(v3s16 p)
2023 {
2024         v3s16 blockpos = getNodeBlockPos(p);
2025         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2026         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2027         if(!block){
2028                 infostream<<"Map::getNodeMetadata(): Need to emerge "
2029                                 <<PP(blockpos)<<std::endl;
2030                 block = emergeBlock(blockpos, false);
2031         }
2032         if(!block){
2033                 warningstream<<"Map::getNodeMetadata(): Block not found"
2034                                 <<std::endl;
2035                 return NULL;
2036         }
2037         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
2038         return meta;
2039 }
2040
2041 bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
2042 {
2043         v3s16 blockpos = getNodeBlockPos(p);
2044         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2045         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2046         if(!block){
2047                 infostream<<"Map::setNodeMetadata(): Need to emerge "
2048                                 <<PP(blockpos)<<std::endl;
2049                 block = emergeBlock(blockpos, false);
2050         }
2051         if(!block){
2052                 warningstream<<"Map::setNodeMetadata(): Block not found"
2053                                 <<std::endl;
2054                 return false;
2055         }
2056         block->m_node_metadata.set(p_rel, meta);
2057         return true;
2058 }
2059
2060 void Map::removeNodeMetadata(v3s16 p)
2061 {
2062         v3s16 blockpos = getNodeBlockPos(p);
2063         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2064         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2065         if(block == NULL)
2066         {
2067                 warningstream<<"Map::removeNodeMetadata(): Block not found"
2068                                 <<std::endl;
2069                 return;
2070         }
2071         block->m_node_metadata.remove(p_rel);
2072 }
2073
2074 NodeTimer Map::getNodeTimer(v3s16 p)
2075 {
2076         v3s16 blockpos = getNodeBlockPos(p);
2077         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2078         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2079         if(!block){
2080                 infostream<<"Map::getNodeTimer(): Need to emerge "
2081                                 <<PP(blockpos)<<std::endl;
2082                 block = emergeBlock(blockpos, false);
2083         }
2084         if(!block){
2085                 warningstream<<"Map::getNodeTimer(): Block not found"
2086                                 <<std::endl;
2087                 return NodeTimer();
2088         }
2089         NodeTimer t = block->m_node_timers.get(p_rel);
2090         NodeTimer nt(t.timeout, t.elapsed, p);
2091         return nt;
2092 }
2093
2094 void Map::setNodeTimer(const NodeTimer &t)
2095 {
2096         v3s16 p = t.position;
2097         v3s16 blockpos = getNodeBlockPos(p);
2098         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2099         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2100         if(!block){
2101                 infostream<<"Map::setNodeTimer(): Need to emerge "
2102                                 <<PP(blockpos)<<std::endl;
2103                 block = emergeBlock(blockpos, false);
2104         }
2105         if(!block){
2106                 warningstream<<"Map::setNodeTimer(): Block not found"
2107                                 <<std::endl;
2108                 return;
2109         }
2110         NodeTimer nt(t.timeout, t.elapsed, p_rel);
2111         block->m_node_timers.set(nt);
2112 }
2113
2114 void Map::removeNodeTimer(v3s16 p)
2115 {
2116         v3s16 blockpos = getNodeBlockPos(p);
2117         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2118         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2119         if(block == NULL)
2120         {
2121                 warningstream<<"Map::removeNodeTimer(): Block not found"
2122                                 <<std::endl;
2123                 return;
2124         }
2125         block->m_node_timers.remove(p_rel);
2126 }
2127
2128 /*
2129         ServerMap
2130 */
2131 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2132         Map(dout_server, gamedef),
2133         settings_mgr(g_settings, savedir + DIR_DELIM + "map_meta.txt"),
2134         m_emerge(emerge),
2135         m_map_metadata_changed(true)
2136 {
2137         verbosestream<<FUNCTION_NAME<<std::endl;
2138
2139         // Tell the EmergeManager about our MapSettingsManager
2140         emerge->map_settings_mgr = &settings_mgr;
2141
2142         /*
2143                 Try to load map; if not found, create a new one.
2144         */
2145
2146         // Determine which database backend to use
2147         std::string conf_path = savedir + DIR_DELIM + "world.mt";
2148         Settings conf;
2149         bool succeeded = conf.readConfigFile(conf_path.c_str());
2150         if (!succeeded || !conf.exists("backend")) {
2151                 // fall back to sqlite3
2152                 conf.set("backend", "sqlite3");
2153         }
2154         std::string backend = conf.get("backend");
2155         dbase = createDatabase(backend, savedir, conf);
2156
2157         if (!conf.updateConfigFile(conf_path.c_str()))
2158                 errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl;
2159
2160         m_savedir = savedir;
2161         m_map_saving_enabled = false;
2162
2163         try
2164         {
2165                 // If directory exists, check contents and load if possible
2166                 if(fs::PathExists(m_savedir))
2167                 {
2168                         // If directory is empty, it is safe to save into it.
2169                         if(fs::GetDirListing(m_savedir).size() == 0)
2170                         {
2171                                 infostream<<"ServerMap: Empty save directory is valid."
2172                                                 <<std::endl;
2173                                 m_map_saving_enabled = true;
2174                         }
2175                         else
2176                         {
2177
2178                                 if (settings_mgr.loadMapMeta()) {
2179                                         infostream << "ServerMap: Metadata loaded from "
2180                                                 << savedir << std::endl;
2181                                 } else {
2182                                         infostream << "ServerMap: Metadata could not be loaded "
2183                                                 "from " << savedir << ", assuming valid save "
2184                                                 "directory." << std::endl;
2185                                 }
2186
2187                                 m_map_saving_enabled = true;
2188                                 // Map loaded, not creating new one
2189                                 return;
2190                         }
2191                 }
2192                 // If directory doesn't exist, it is safe to save to it
2193                 else{
2194                         m_map_saving_enabled = true;
2195                 }
2196         }
2197         catch(std::exception &e)
2198         {
2199                 warningstream<<"ServerMap: Failed to load map from "<<savedir
2200                                 <<", exception: "<<e.what()<<std::endl;
2201                 infostream<<"Please remove the map or fix it."<<std::endl;
2202                 warningstream<<"Map saving will be disabled."<<std::endl;
2203         }
2204
2205         infostream<<"Initializing new map."<<std::endl;
2206
2207         // Create zero sector
2208         emergeSector(v2s16(0,0));
2209
2210         // Initially write whole map
2211         save(MOD_STATE_CLEAN);
2212 }
2213
2214 ServerMap::~ServerMap()
2215 {
2216         verbosestream<<FUNCTION_NAME<<std::endl;
2217
2218         try
2219         {
2220                 if(m_map_saving_enabled)
2221                 {
2222                         // Save only changed parts
2223                         save(MOD_STATE_WRITE_AT_UNLOAD);
2224                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2225                 }
2226                 else
2227                 {
2228                         infostream<<"ServerMap: Map not saved"<<std::endl;
2229                 }
2230         }
2231         catch(std::exception &e)
2232         {
2233                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2234                                 <<", exception: "<<e.what()<<std::endl;
2235         }
2236
2237         /*
2238                 Close database if it was opened
2239         */
2240         delete dbase;
2241
2242 #if 0
2243         /*
2244                 Free all MapChunks
2245         */
2246         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2247         for(; i.atEnd() == false; i++)
2248         {
2249                 MapChunk *chunk = i.getNode()->getValue();
2250                 delete chunk;
2251         }
2252 #endif
2253 }
2254
2255 MapgenParams *ServerMap::getMapgenParams()
2256 {
2257         // getMapgenParams() should only ever be called after Server is initialized
2258         assert(settings_mgr.mapgen_params != NULL);
2259         return settings_mgr.mapgen_params;
2260 }
2261
2262 u64 ServerMap::getSeed()
2263 {
2264         return getMapgenParams()->seed;
2265 }
2266
2267 s16 ServerMap::getWaterLevel()
2268 {
2269         return getMapgenParams()->water_level;
2270 }
2271
2272 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
2273 {
2274         s16 csize = getMapgenParams()->chunksize;
2275         v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
2276         v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
2277
2278         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
2279         EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
2280
2281         v3s16 extra_borders(1, 1, 1);
2282         v3s16 full_bpmin = bpmin - extra_borders;
2283         v3s16 full_bpmax = bpmax + extra_borders;
2284
2285         // Do nothing if not inside limits (+-1 because of neighbors)
2286         if (blockpos_over_limit(full_bpmin) ||
2287                 blockpos_over_limit(full_bpmax))
2288                 return false;
2289
2290         data->seed = getSeed();
2291         data->blockpos_min = bpmin;
2292         data->blockpos_max = bpmax;
2293         data->blockpos_requested = blockpos;
2294         data->nodedef = m_gamedef->ndef();
2295
2296         /*
2297                 Create the whole area of this and the neighboring blocks
2298         */
2299         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
2300         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
2301                 v2s16 sectorpos(x, z);
2302                 // Sector metadata is loaded from disk if not already loaded.
2303                 ServerMapSector *sector = createSector(sectorpos);
2304                 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
2305
2306                 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
2307                         v3s16 p(x, y, z);
2308
2309                         MapBlock *block = emergeBlock(p, false);
2310                         if (block == NULL) {
2311                                 block = createBlock(p);
2312
2313                                 // Block gets sunlight if this is true.
2314                                 // Refer to the map generator heuristics.
2315                                 bool ug = m_emerge->isBlockUnderground(p);
2316                                 block->setIsUnderground(ug);
2317                         }
2318                 }
2319         }
2320
2321         /*
2322                 Now we have a big empty area.
2323
2324                 Make a ManualMapVoxelManipulator that contains this and the
2325                 neighboring blocks
2326         */
2327
2328         data->vmanip = new MMVManip(this);
2329         data->vmanip->initialEmerge(full_bpmin, full_bpmax);
2330
2331         // Note: we may need this again at some point.
2332 #if 0
2333         // Ensure none of the blocks to be generated were marked as
2334         // containing CONTENT_IGNORE
2335         for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2336                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2337                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2338                                 core::map<v3s16, u8>::Node *n;
2339                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2340                                 if (n == NULL)
2341                                         continue;
2342                                 u8 flags = n->getValue();
2343                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2344                                 n->setValue(flags);
2345                         }
2346                 }
2347         }
2348 #endif
2349
2350         // Data is ready now.
2351         return true;
2352 }
2353
2354 void ServerMap::finishBlockMake(BlockMakeData *data,
2355         std::map<v3s16, MapBlock*> *changed_blocks)
2356 {
2357         v3s16 bpmin = data->blockpos_min;
2358         v3s16 bpmax = data->blockpos_max;
2359
2360         v3s16 extra_borders(1, 1, 1);
2361         v3s16 full_bpmin = bpmin - extra_borders;
2362         v3s16 full_bpmax = bpmax + extra_borders;
2363
2364         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
2365         EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
2366
2367         /*
2368                 Set lighting to non-expired state in all of them.
2369                 This is cheating, but it is not fast enough if all of them
2370                 would actually be updated.
2371         */
2372         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
2373         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
2374         for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
2375                 MapBlock *block = emergeBlock(v3s16(x, y, z), false);
2376                 if (!block)
2377                         continue;
2378
2379                 block->setLightingExpired(false);
2380         }
2381
2382         /*
2383                 Blit generated stuff to map
2384                 NOTE: blitBackAll adds nearly everything to changed_blocks
2385         */
2386         data->vmanip->blitBackAll(changed_blocks);
2387
2388         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
2389                 << changed_blocks->size());
2390
2391         /*
2392                 Copy transforming liquid information
2393         */
2394         while (data->transforming_liquid.size()) {
2395                 m_transforming_liquid.push_back(data->transforming_liquid.front());
2396                 data->transforming_liquid.pop_front();
2397         }
2398
2399         for (std::map<v3s16, MapBlock *>::iterator
2400                         it = changed_blocks->begin();
2401                         it != changed_blocks->end(); ++it) {
2402                 MapBlock *block = it->second;
2403                 if (!block)
2404                         continue;
2405                 /*
2406                         Update day/night difference cache of the MapBlocks
2407                 */
2408                 block->expireDayNightDiff();
2409                 /*
2410                         Set block as modified
2411                 */
2412                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2413                         MOD_REASON_EXPIRE_DAYNIGHTDIFF);
2414         }
2415
2416         /*
2417                 Set central blocks as generated
2418         */
2419         for (s16 x = bpmin.X; x <= bpmax.X; x++)
2420         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
2421         for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
2422                 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
2423                 if (!block)
2424                         continue;
2425
2426                 block->setGenerated(true);
2427         }
2428
2429         /*
2430                 Save changed parts of map
2431                 NOTE: Will be saved later.
2432         */
2433         //save(MOD_STATE_WRITE_AT_UNLOAD);
2434 }
2435
2436 ServerMapSector *ServerMap::createSector(v2s16 p2d)
2437 {
2438         DSTACKF("%s: p2d=(%d,%d)",
2439                         FUNCTION_NAME,
2440                         p2d.X, p2d.Y);
2441
2442         /*
2443                 Check if it exists already in memory
2444         */
2445         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2446         if(sector != NULL)
2447                 return sector;
2448
2449         /*
2450                 Try to load it from disk (with blocks)
2451         */
2452         //if(loadSectorFull(p2d) == true)
2453
2454         /*
2455                 Try to load metadata from disk
2456         */
2457 #if 0
2458         if(loadSectorMeta(p2d) == true)
2459         {
2460                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2461                 if(sector == NULL)
2462                 {
2463                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2464                         throw InvalidPositionException("");
2465                 }
2466                 return sector;
2467         }
2468 #endif
2469         /*
2470                 Do not create over-limit
2471         */
2472         const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
2473                 g_settings->getU16("map_generation_limit"));
2474         if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
2475                         || p2d.X >  map_gen_limit / MAP_BLOCKSIZE
2476                         || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
2477                         || p2d.Y >  map_gen_limit / MAP_BLOCKSIZE)
2478                 throw InvalidPositionException("createSector(): pos. over limit");
2479
2480         /*
2481                 Generate blank sector
2482         */
2483
2484         sector = new ServerMapSector(this, p2d, m_gamedef);
2485
2486         // Sector position on map in nodes
2487         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2488
2489         /*
2490                 Insert to container
2491         */
2492         m_sectors[p2d] = sector;
2493
2494         return sector;
2495 }
2496
2497 #if 0
2498 /*
2499         This is a quick-hand function for calling makeBlock().
2500 */
2501 MapBlock * ServerMap::generateBlock(
2502                 v3s16 p,
2503                 std::map<v3s16, MapBlock*> &modified_blocks
2504 )
2505 {
2506         DSTACKF("%s: p=(%d,%d,%d)", FUNCTION_NAME, p.X, p.Y, p.Z);
2507
2508         /*infostream<<"generateBlock(): "
2509                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2510                         <<std::endl;*/
2511
2512         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2513
2514         TimeTaker timer("generateBlock");
2515
2516         //MapBlock *block = original_dummy;
2517
2518         v2s16 p2d(p.X, p.Z);
2519         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2520
2521         /*
2522                 Do not generate over-limit
2523         */
2524         if(blockpos_over_limit(p))
2525         {
2526                 infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
2527                 throw InvalidPositionException("generateBlock(): pos. over limit");
2528         }
2529
2530         /*
2531                 Create block make data
2532         */
2533         BlockMakeData data;
2534         initBlockMake(&data, p);
2535
2536         /*
2537                 Generate block
2538         */
2539         {
2540                 TimeTaker t("mapgen::make_block()");
2541                 mapgen->makeChunk(&data);
2542                 //mapgen::make_block(&data);
2543
2544                 if(enable_mapgen_debug_info == false)
2545                         t.stop(true); // Hide output
2546         }
2547
2548         /*
2549                 Blit data back on map, update lighting, add mobs and whatever this does
2550         */
2551         finishBlockMake(&data, modified_blocks);
2552
2553         /*
2554                 Get central block
2555         */
2556         MapBlock *block = getBlockNoCreateNoEx(p);
2557
2558 #if 0
2559         /*
2560                 Check result
2561         */
2562         if(block)
2563         {
2564                 bool erroneus_content = false;
2565                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2566                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2567                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2568                 {
2569                         v3s16 p(x0,y0,z0);
2570                         MapNode n = block->getNode(p);
2571                         if(n.getContent() == CONTENT_IGNORE)
2572                         {
2573                                 infostream<<"CONTENT_IGNORE at "
2574                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2575                                                 <<std::endl;
2576                                 erroneus_content = true;
2577                                 assert(0);
2578                         }
2579                 }
2580                 if(erroneus_content)
2581                 {
2582                         assert(0);
2583                 }
2584         }
2585 #endif
2586
2587 #if 0
2588         /*
2589                 Generate a completely empty block
2590         */
2591         if(block)
2592         {
2593                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2594                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2595                 {
2596                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2597                         {
2598                                 MapNode n;
2599                                 n.setContent(CONTENT_AIR);
2600                                 block->setNode(v3s16(x0,y0,z0), n);
2601                         }
2602                 }
2603         }
2604 #endif
2605
2606         if(enable_mapgen_debug_info == false)
2607                 timer.stop(true); // Hide output
2608
2609         return block;
2610 }
2611 #endif
2612
2613 MapBlock * ServerMap::createBlock(v3s16 p)
2614 {
2615         DSTACKF("%s: p=(%d,%d,%d)",
2616                         FUNCTION_NAME, p.X, p.Y, p.Z);
2617
2618         /*
2619                 Do not create over-limit
2620         */
2621         if (blockpos_over_limit(p))
2622                 throw InvalidPositionException("createBlock(): pos. over limit");
2623
2624         v2s16 p2d(p.X, p.Z);
2625         s16 block_y = p.Y;
2626         /*
2627                 This will create or load a sector if not found in memory.
2628                 If block exists on disk, it will be loaded.
2629
2630                 NOTE: On old save formats, this will be slow, as it generates
2631                       lighting on blocks for them.
2632         */
2633         ServerMapSector *sector;
2634         try {
2635                 sector = (ServerMapSector*)createSector(p2d);
2636                 assert(sector->getId() == MAPSECTOR_SERVER);
2637         }
2638         catch(InvalidPositionException &e)
2639         {
2640                 infostream<<"createBlock: createSector() failed"<<std::endl;
2641                 throw e;
2642         }
2643         /*
2644                 NOTE: This should not be done, or at least the exception
2645                 should not be passed on as std::exception, because it
2646                 won't be catched at all.
2647         */
2648         /*catch(std::exception &e)
2649         {
2650                 infostream<<"createBlock: createSector() failed: "
2651                                 <<e.what()<<std::endl;
2652                 throw e;
2653         }*/
2654
2655         /*
2656                 Try to get a block from the sector
2657         */
2658
2659         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2660         if(block)
2661         {
2662                 if(block->isDummy())
2663                         block->unDummify();
2664                 return block;
2665         }
2666         // Create blank
2667         block = sector->createBlankBlock(block_y);
2668
2669         return block;
2670 }
2671
2672 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2673 {
2674         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2675                         FUNCTION_NAME,
2676                         p.X, p.Y, p.Z, create_blank);
2677
2678         {
2679                 MapBlock *block = getBlockNoCreateNoEx(p);
2680                 if(block && block->isDummy() == false)
2681                         return block;
2682         }
2683
2684         {
2685                 MapBlock *block = loadBlock(p);
2686                 if(block)
2687                         return block;
2688         }
2689
2690         if (create_blank) {
2691                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2692                 MapBlock *block = sector->createBlankBlock(p.Y);
2693
2694                 return block;
2695         }
2696
2697 #if 0
2698         if(allow_generate)
2699         {
2700                 std::map<v3s16, MapBlock*> modified_blocks;
2701                 MapBlock *block = generateBlock(p, modified_blocks);
2702                 if(block)
2703                 {
2704                         MapEditEvent event;
2705                         event.type = MEET_OTHER;
2706                         event.p = p;
2707
2708                         // Copy modified_blocks to event
2709                         for(std::map<v3s16, MapBlock*>::iterator
2710                                         i = modified_blocks.begin();
2711                                         i != modified_blocks.end(); ++i)
2712                         {
2713                                 event.modified_blocks.insert(i->first);
2714                         }
2715
2716                         // Queue event
2717                         dispatchEvent(&event);
2718
2719                         return block;
2720                 }
2721         }
2722 #endif
2723
2724         return NULL;
2725 }
2726
2727 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
2728 {
2729         MapBlock *block = getBlockNoCreateNoEx(p3d);
2730         if (block == NULL)
2731                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
2732
2733         return block;
2734 }
2735
2736 void ServerMap::prepareBlock(MapBlock *block) {
2737 }
2738
2739 // N.B.  This requires no synchronization, since data will not be modified unless
2740 // the VoxelManipulator being updated belongs to the same thread.
2741 void ServerMap::updateVManip(v3s16 pos)
2742 {
2743         Mapgen *mg = m_emerge->getCurrentMapgen();
2744         if (!mg)
2745                 return;
2746
2747         MMVManip *vm = mg->vm;
2748         if (!vm)
2749                 return;
2750
2751         if (!vm->m_area.contains(pos))
2752                 return;
2753
2754         s32 idx = vm->m_area.index(pos);
2755         vm->m_data[idx] = getNodeNoEx(pos);
2756         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
2757
2758         vm->m_is_dirty = true;
2759 }
2760
2761 s16 ServerMap::findGroundLevel(v2s16 p2d)
2762 {
2763 #if 0
2764         /*
2765                 Uh, just do something random...
2766         */
2767         // Find existing map from top to down
2768         s16 max=63;
2769         s16 min=-64;
2770         v3s16 p(p2d.X, max, p2d.Y);
2771         for(; p.Y>min; p.Y--)
2772         {
2773                 MapNode n = getNodeNoEx(p);
2774                 if(n.getContent() != CONTENT_IGNORE)
2775                         break;
2776         }
2777         if(p.Y == min)
2778                 goto plan_b;
2779         // If this node is not air, go to plan b
2780         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2781                 goto plan_b;
2782         // Search existing walkable and return it
2783         for(; p.Y>min; p.Y--)
2784         {
2785                 MapNode n = getNodeNoEx(p);
2786                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2787                         return p.Y;
2788         }
2789
2790         // Move to plan b
2791 plan_b:
2792 #endif
2793
2794         /*
2795                 Determine from map generator noise functions
2796         */
2797
2798         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2799         return level;
2800
2801         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2802         //return (s16)level;
2803 }
2804
2805 bool ServerMap::loadFromFolders() {
2806         if (!dbase->initialized() &&
2807                         !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2808                 return true;
2809         return false;
2810 }
2811
2812 void ServerMap::createDirs(std::string path)
2813 {
2814         if(fs::CreateAllDirs(path) == false)
2815         {
2816                 m_dout<<"ServerMap: Failed to create directory "
2817                                 <<"\""<<path<<"\""<<std::endl;
2818                 throw BaseException("ServerMap failed to create directory");
2819         }
2820 }
2821
2822 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2823 {
2824         char cc[9];
2825         switch(layout)
2826         {
2827                 case 1:
2828                         snprintf(cc, 9, "%.4x%.4x",
2829                                 (unsigned int) pos.X & 0xffff,
2830                                 (unsigned int) pos.Y & 0xffff);
2831
2832                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2833                 case 2:
2834                         snprintf(cc, 9, (std::string("%.3x") + DIR_DELIM + "%.3x").c_str(),
2835                                 (unsigned int) pos.X & 0xfff,
2836                                 (unsigned int) pos.Y & 0xfff);
2837
2838                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2839                 default:
2840                         assert(false);
2841                         return "";
2842         }
2843 }
2844
2845 v2s16 ServerMap::getSectorPos(std::string dirname)
2846 {
2847         unsigned int x = 0, y = 0;
2848         int r;
2849         std::string component;
2850         fs::RemoveLastPathComponent(dirname, &component, 1);
2851         if(component.size() == 8)
2852         {
2853                 // Old layout
2854                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
2855         }
2856         else if(component.size() == 3)
2857         {
2858                 // New layout
2859                 fs::RemoveLastPathComponent(dirname, &component, 2);
2860                 r = sscanf(component.c_str(), (std::string("%3x") + DIR_DELIM + "%3x").c_str(), &x, &y);
2861                 // Sign-extend the 12 bit values up to 16 bits...
2862                 if(x & 0x800) x |= 0xF000;
2863                 if(y & 0x800) y |= 0xF000;
2864         }
2865         else
2866         {
2867                 r = -1;
2868         }
2869
2870         FATAL_ERROR_IF(r != 2, "getSectorPos()");
2871         v2s16 pos((s16)x, (s16)y);
2872         return pos;
2873 }
2874
2875 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2876 {
2877         v2s16 p2d = getSectorPos(sectordir);
2878
2879         if(blockfile.size() != 4){
2880                 throw InvalidFilenameException("Invalid block filename");
2881         }
2882         unsigned int y;
2883         int r = sscanf(blockfile.c_str(), "%4x", &y);
2884         if(r != 1)
2885                 throw InvalidFilenameException("Invalid block filename");
2886         return v3s16(p2d.X, y, p2d.Y);
2887 }
2888
2889 std::string ServerMap::getBlockFilename(v3s16 p)
2890 {
2891         char cc[5];
2892         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2893         return cc;
2894 }
2895
2896 void ServerMap::save(ModifiedState save_level)
2897 {
2898         DSTACK(FUNCTION_NAME);
2899         if(m_map_saving_enabled == false) {
2900                 warningstream<<"Not saving map, saving disabled."<<std::endl;
2901                 return;
2902         }
2903
2904         if(save_level == MOD_STATE_CLEAN)
2905                 infostream<<"ServerMap: Saving whole map, this can take time."
2906                                 <<std::endl;
2907
2908         if (m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
2909                 if (settings_mgr.saveMapMeta())
2910                         m_map_metadata_changed = false;
2911         }
2912
2913         // Profile modified reasons
2914         Profiler modprofiler;
2915
2916         u32 sector_meta_count = 0;
2917         u32 block_count = 0;
2918         u32 block_count_all = 0; // Number of blocks in memory
2919
2920         // Don't do anything with sqlite unless something is really saved
2921         bool save_started = false;
2922
2923         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
2924                 i != m_sectors.end(); ++i) {
2925                 ServerMapSector *sector = (ServerMapSector*)i->second;
2926                 assert(sector->getId() == MAPSECTOR_SERVER);
2927
2928                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN) {
2929                         saveSectorMeta(sector);
2930                         sector_meta_count++;
2931                 }
2932
2933                 MapBlockVect blocks;
2934                 sector->getBlocks(blocks);
2935
2936                 for(MapBlockVect::iterator j = blocks.begin();
2937                         j != blocks.end(); ++j) {
2938                         MapBlock *block = *j;
2939
2940                         block_count_all++;
2941
2942                         if(block->getModified() >= (u32)save_level) {
2943                                 // Lazy beginSave()
2944                                 if(!save_started) {
2945                                         beginSave();
2946                                         save_started = true;
2947                                 }
2948
2949                                 modprofiler.add(block->getModifiedReasonString(), 1);
2950
2951                                 saveBlock(block);
2952                                 block_count++;
2953
2954                                 /*infostream<<"ServerMap: Written block ("
2955                                                 <<block->getPos().X<<","
2956                                                 <<block->getPos().Y<<","
2957                                                 <<block->getPos().Z<<")"
2958                                                 <<std::endl;*/
2959                         }
2960                 }
2961         }
2962
2963         if(save_started)
2964                 endSave();
2965
2966         /*
2967                 Only print if something happened or saved whole map
2968         */
2969         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
2970                         || block_count != 0) {
2971                 infostream<<"ServerMap: Written: "
2972                                 <<sector_meta_count<<" sector metadata files, "
2973                                 <<block_count<<" block files"
2974                                 <<", "<<block_count_all<<" blocks in memory."
2975                                 <<std::endl;
2976                 PrintInfo(infostream); // ServerMap/ClientMap:
2977                 infostream<<"Blocks modified by: "<<std::endl;
2978                 modprofiler.print(infostream);
2979         }
2980 }
2981
2982 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
2983 {
2984         if (loadFromFolders()) {
2985                 errorstream << "Map::listAllLoadableBlocks(): Result will be missing "
2986                                 << "all blocks that are stored in flat files." << std::endl;
2987         }
2988         dbase->listAllLoadableBlocks(dst);
2989 }
2990
2991 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
2992 {
2993         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
2994                 si != m_sectors.end(); ++si)
2995         {
2996                 MapSector *sector = si->second;
2997
2998                 MapBlockVect blocks;
2999                 sector->getBlocks(blocks);
3000
3001                 for(MapBlockVect::iterator i = blocks.begin();
3002                                 i != blocks.end(); ++i) {
3003                         v3s16 p = (*i)->getPos();
3004                         dst.push_back(p);
3005                 }
3006         }
3007 }
3008
3009 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3010 {
3011         DSTACK(FUNCTION_NAME);
3012         // Format used for writing
3013         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3014         // Get destination
3015         v2s16 pos = sector->getPos();
3016         std::string dir = getSectorDir(pos);
3017         createDirs(dir);
3018
3019         std::string fullpath = dir + DIR_DELIM + "meta";
3020         std::ostringstream ss(std::ios_base::binary);
3021
3022         sector->serialize(ss, version);
3023
3024         if(!fs::safeWriteToFile(fullpath, ss.str()))
3025                 throw FileNotGoodException("Cannot write sector metafile");
3026
3027         sector->differs_from_disk = false;
3028 }
3029
3030 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3031 {
3032         DSTACK(FUNCTION_NAME);
3033         // Get destination
3034         v2s16 p2d = getSectorPos(sectordir);
3035
3036         ServerMapSector *sector = NULL;
3037
3038         std::string fullpath = sectordir + DIR_DELIM + "meta";
3039         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3040         if(is.good() == false)
3041         {
3042                 // If the directory exists anyway, it probably is in some old
3043                 // format. Just go ahead and create the sector.
3044                 if(fs::PathExists(sectordir))
3045                 {
3046                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3047                                         <<fullpath<<" doesn't exist but directory does."
3048                                         <<" Continuing with a sector with no metadata."
3049                                         <<std::endl;*/
3050                         sector = new ServerMapSector(this, p2d, m_gamedef);
3051                         m_sectors[p2d] = sector;
3052                 }
3053                 else
3054                 {
3055                         throw FileNotGoodException("Cannot open sector metafile");
3056                 }
3057         }
3058         else
3059         {
3060                 sector = ServerMapSector::deSerialize
3061                                 (is, this, p2d, m_sectors, m_gamedef);
3062                 if(save_after_load)
3063                         saveSectorMeta(sector);
3064         }
3065
3066         sector->differs_from_disk = false;
3067
3068         return sector;
3069 }
3070
3071 bool ServerMap::loadSectorMeta(v2s16 p2d)
3072 {
3073         DSTACK(FUNCTION_NAME);
3074
3075         // The directory layout we're going to load from.
3076         //  1 - original sectors/xxxxzzzz/
3077         //  2 - new sectors2/xxx/zzz/
3078         //  If we load from anything but the latest structure, we will
3079         //  immediately save to the new one, and remove the old.
3080         int loadlayout = 1;
3081         std::string sectordir1 = getSectorDir(p2d, 1);
3082         std::string sectordir;
3083         if(fs::PathExists(sectordir1))
3084         {
3085                 sectordir = sectordir1;
3086         }
3087         else
3088         {
3089                 loadlayout = 2;
3090                 sectordir = getSectorDir(p2d, 2);
3091         }
3092
3093         try{
3094                 loadSectorMeta(sectordir, loadlayout != 2);
3095         }
3096         catch(InvalidFilenameException &e)
3097         {
3098                 return false;
3099         }
3100         catch(FileNotGoodException &e)
3101         {
3102                 return false;
3103         }
3104         catch(std::exception &e)
3105         {
3106                 return false;
3107         }
3108
3109         return true;
3110 }
3111
3112 #if 0
3113 bool ServerMap::loadSectorFull(v2s16 p2d)
3114 {
3115         DSTACK(FUNCTION_NAME);
3116
3117         MapSector *sector = NULL;
3118
3119         // The directory layout we're going to load from.
3120         //  1 - original sectors/xxxxzzzz/
3121         //  2 - new sectors2/xxx/zzz/
3122         //  If we load from anything but the latest structure, we will
3123         //  immediately save to the new one, and remove the old.
3124         int loadlayout = 1;
3125         std::string sectordir1 = getSectorDir(p2d, 1);
3126         std::string sectordir;
3127         if(fs::PathExists(sectordir1))
3128         {
3129                 sectordir = sectordir1;
3130         }
3131         else
3132         {
3133                 loadlayout = 2;
3134                 sectordir = getSectorDir(p2d, 2);
3135         }
3136
3137         try{
3138                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3139         }
3140         catch(InvalidFilenameException &e)
3141         {
3142                 return false;
3143         }
3144         catch(FileNotGoodException &e)
3145         {
3146                 return false;
3147         }
3148         catch(std::exception &e)
3149         {
3150                 return false;
3151         }
3152
3153         /*
3154                 Load blocks
3155         */
3156         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3157                         (sectordir);
3158         std::vector<fs::DirListNode>::iterator i2;
3159         for(i2=list2.begin(); i2!=list2.end(); i2++)
3160         {
3161                 // We want files
3162                 if(i2->dir)
3163                         continue;
3164                 try{
3165                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3166                 }
3167                 catch(InvalidFilenameException &e)
3168                 {
3169                         // This catches unknown crap in directory
3170                 }
3171         }
3172
3173         if(loadlayout != 2)
3174         {
3175                 infostream<<"Sector converted to new layout - deleting "<<
3176                         sectordir1<<std::endl;
3177                 fs::RecursiveDelete(sectordir1);
3178         }
3179
3180         return true;
3181 }
3182 #endif
3183
3184 Database *ServerMap::createDatabase(
3185         const std::string &name,
3186         const std::string &savedir,
3187         Settings &conf)
3188 {
3189         if (name == "sqlite3")
3190                 return new Database_SQLite3(savedir);
3191         if (name == "dummy")
3192                 return new Database_Dummy();
3193         #if USE_LEVELDB
3194         else if (name == "leveldb")
3195                 return new Database_LevelDB(savedir);
3196         #endif
3197         #if USE_REDIS
3198         else if (name == "redis")
3199                 return new Database_Redis(conf);
3200         #endif
3201         #if USE_POSTGRESQL
3202         else if (name == "postgresql")
3203                 return new Database_PostgreSQL(conf);
3204         #endif
3205         else
3206                 throw BaseException(std::string("Database backend ") + name + " not supported.");
3207 }
3208
3209 void ServerMap::beginSave()
3210 {
3211         dbase->beginSave();
3212 }
3213
3214 void ServerMap::endSave()
3215 {
3216         dbase->endSave();
3217 }
3218
3219 bool ServerMap::saveBlock(MapBlock *block)
3220 {
3221         return saveBlock(block, dbase);
3222 }
3223
3224 bool ServerMap::saveBlock(MapBlock *block, Database *db)
3225 {
3226         v3s16 p3d = block->getPos();
3227
3228         // Dummy blocks are not written
3229         if (block->isDummy()) {
3230                 warningstream << "saveBlock: Not writing dummy block "
3231                         << PP(p3d) << std::endl;
3232                 return true;
3233         }
3234
3235         // Format used for writing
3236         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3237
3238         /*
3239                 [0] u8 serialization version
3240                 [1] data
3241         */
3242         std::ostringstream o(std::ios_base::binary);
3243         o.write((char*) &version, 1);
3244         block->serialize(o, version, true);
3245
3246         std::string data = o.str();
3247         bool ret = db->saveBlock(p3d, data);
3248         if (ret) {
3249                 // We just wrote it to the disk so clear modified flag
3250                 block->resetModified();
3251         }
3252         return ret;
3253 }
3254
3255 void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
3256                 MapSector *sector, bool save_after_load)
3257 {
3258         DSTACK(FUNCTION_NAME);
3259
3260         std::string fullpath = sectordir + DIR_DELIM + blockfile;
3261         try {
3262
3263                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3264                 if(is.good() == false)
3265                         throw FileNotGoodException("Cannot open block file");
3266
3267                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3268                 v2s16 p2d(p3d.X, p3d.Z);
3269
3270                 assert(sector->getPos() == p2d);
3271
3272                 u8 version = SER_FMT_VER_INVALID;
3273                 is.read((char*)&version, 1);
3274
3275                 if(is.fail())
3276                         throw SerializationError("ServerMap::loadBlock(): Failed"
3277                                         " to read MapBlock version");
3278
3279                 /*u32 block_size = MapBlock::serializedLength(version);
3280                 SharedBuffer<u8> data(block_size);
3281                 is.read((char*)*data, block_size);*/
3282
3283                 // This will always return a sector because we're the server
3284                 //MapSector *sector = emergeSector(p2d);
3285
3286                 MapBlock *block = NULL;
3287                 bool created_new = false;
3288                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3289                 if(block == NULL)
3290                 {
3291                         block = sector->createBlankBlockNoInsert(p3d.Y);
3292                         created_new = true;
3293                 }
3294
3295                 // Read basic data
3296                 block->deSerialize(is, version, true);
3297
3298                 // If it's a new block, insert it to the map
3299                 if(created_new)
3300                         sector->insertBlock(block);
3301
3302                 /*
3303                         Save blocks loaded in old format in new format
3304                 */
3305
3306                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3307                 {
3308                         saveBlock(block);
3309
3310                         // Should be in database now, so delete the old file
3311                         fs::RecursiveDelete(fullpath);
3312                 }
3313
3314                 // We just loaded it from the disk, so it's up-to-date.
3315                 block->resetModified();
3316
3317         }
3318         catch(SerializationError &e)
3319         {
3320                 warningstream<<"Invalid block data on disk "
3321                                 <<"fullpath="<<fullpath
3322                                 <<" (SerializationError). "
3323                                 <<"what()="<<e.what()
3324                                 <<std::endl;
3325                                 // Ignoring. A new one will be generated.
3326                 abort();
3327
3328                 // TODO: Backup file; name is in fullpath.
3329         }
3330 }
3331
3332 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3333 {
3334         DSTACK(FUNCTION_NAME);
3335
3336         try {
3337                 std::istringstream is(*blob, std::ios_base::binary);
3338
3339                 u8 version = SER_FMT_VER_INVALID;
3340                 is.read((char*)&version, 1);
3341
3342                 if(is.fail())
3343                         throw SerializationError("ServerMap::loadBlock(): Failed"
3344                                         " to read MapBlock version");
3345
3346                 /*u32 block_size = MapBlock::serializedLength(version);
3347                 SharedBuffer<u8> data(block_size);
3348                 is.read((char*)*data, block_size);*/
3349
3350                 // This will always return a sector because we're the server
3351                 //MapSector *sector = emergeSector(p2d);
3352
3353                 MapBlock *block = NULL;
3354                 bool created_new = false;
3355                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3356                 if(block == NULL)
3357                 {
3358                         block = sector->createBlankBlockNoInsert(p3d.Y);
3359                         created_new = true;
3360                 }
3361
3362                 // Read basic data
3363                 block->deSerialize(is, version, true);
3364
3365                 // If it's a new block, insert it to the map
3366                 if(created_new)
3367                         sector->insertBlock(block);
3368
3369                 /*
3370                         Save blocks loaded in old format in new format
3371                 */
3372
3373                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3374                 // Only save if asked to; no need to update version
3375                 if(save_after_load)
3376                         saveBlock(block);
3377
3378                 // We just loaded it from, so it's up-to-date.
3379                 block->resetModified();
3380
3381         }
3382         catch(SerializationError &e)
3383         {
3384                 errorstream<<"Invalid block data in database"
3385                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3386                                 <<" (SerializationError): "<<e.what()<<std::endl;
3387
3388                 // TODO: Block should be marked as invalid in memory so that it is
3389                 // not touched but the game can run
3390
3391                 if(g_settings->getBool("ignore_world_load_errors")){
3392                         errorstream<<"Ignoring block load error. Duck and cover! "
3393                                         <<"(ignore_world_load_errors)"<<std::endl;
3394                 } else {
3395                         throw SerializationError("Invalid block data in database");
3396                 }
3397         }
3398 }
3399
3400 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3401 {
3402         DSTACK(FUNCTION_NAME);
3403
3404         v2s16 p2d(blockpos.X, blockpos.Z);
3405
3406         std::string ret;
3407         dbase->loadBlock(blockpos, &ret);
3408         if (ret != "") {
3409                 loadBlock(&ret, blockpos, createSector(p2d), false);
3410                 return getBlockNoCreateNoEx(blockpos);
3411         }
3412         // Not found in database, try the files
3413
3414         // The directory layout we're going to load from.
3415         //  1 - original sectors/xxxxzzzz/
3416         //  2 - new sectors2/xxx/zzz/
3417         //  If we load from anything but the latest structure, we will
3418         //  immediately save to the new one, and remove the old.
3419         int loadlayout = 1;
3420         std::string sectordir1 = getSectorDir(p2d, 1);
3421         std::string sectordir;
3422         if(fs::PathExists(sectordir1))
3423         {
3424                 sectordir = sectordir1;
3425         }
3426         else
3427         {
3428                 loadlayout = 2;
3429                 sectordir = getSectorDir(p2d, 2);
3430         }
3431
3432         /*
3433                 Make sure sector is loaded
3434         */
3435
3436         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3437         if(sector == NULL)
3438         {
3439                 try{
3440                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3441                 }
3442                 catch(InvalidFilenameException &e)
3443                 {
3444                         return NULL;
3445                 }
3446                 catch(FileNotGoodException &e)
3447                 {
3448                         return NULL;
3449                 }
3450                 catch(std::exception &e)
3451                 {
3452                         return NULL;
3453                 }
3454         }
3455
3456         /*
3457                 Make sure file exists
3458         */
3459
3460         std::string blockfilename = getBlockFilename(blockpos);
3461         if(fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
3462                 return NULL;
3463
3464         /*
3465                 Load block and save it to the database
3466         */
3467         loadBlock(sectordir, blockfilename, sector, true);
3468         return getBlockNoCreateNoEx(blockpos);
3469 }
3470
3471 bool ServerMap::deleteBlock(v3s16 blockpos)
3472 {
3473         if (!dbase->deleteBlock(blockpos))
3474                 return false;
3475
3476         MapBlock *block = getBlockNoCreateNoEx(blockpos);
3477         if (block) {
3478                 v2s16 p2d(blockpos.X, blockpos.Z);
3479                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3480                 if (!sector)
3481                         return false;
3482                 sector->deleteBlock(block);
3483         }
3484
3485         return true;
3486 }
3487
3488 void ServerMap::PrintInfo(std::ostream &out)
3489 {
3490         out<<"ServerMap: ";
3491 }
3492
3493 MMVManip::MMVManip(Map *map):
3494                 VoxelManipulator(),
3495                 m_is_dirty(false),
3496                 m_create_area(false),
3497                 m_map(map)
3498 {
3499 }
3500
3501 MMVManip::~MMVManip()
3502 {
3503 }
3504
3505 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
3506         bool load_if_inexistent)
3507 {
3508         TimeTaker timer1("initialEmerge", &emerge_time);
3509
3510         // Units of these are MapBlocks
3511         v3s16 p_min = blockpos_min;
3512         v3s16 p_max = blockpos_max;
3513
3514         VoxelArea block_area_nodes
3515                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3516
3517         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3518         if(size_MB >= 1)
3519         {
3520                 infostream<<"initialEmerge: area: ";
3521                 block_area_nodes.print(infostream);
3522                 infostream<<" ("<<size_MB<<"MB)";
3523                 infostream<<std::endl;
3524         }
3525
3526         addArea(block_area_nodes);
3527
3528         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3529         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3530         for(s32 x=p_min.X; x<=p_max.X; x++)
3531         {
3532                 u8 flags = 0;
3533                 MapBlock *block;
3534                 v3s16 p(x,y,z);
3535                 std::map<v3s16, u8>::iterator n;
3536                 n = m_loaded_blocks.find(p);
3537                 if(n != m_loaded_blocks.end())
3538                         continue;
3539
3540                 bool block_data_inexistent = false;
3541                 try
3542                 {
3543                         TimeTaker timer1("emerge load", &emerge_load_time);
3544
3545                         block = m_map->getBlockNoCreate(p);
3546                         if(block->isDummy())
3547                                 block_data_inexistent = true;
3548                         else
3549                                 block->copyTo(*this);
3550                 }
3551                 catch(InvalidPositionException &e)
3552                 {
3553                         block_data_inexistent = true;
3554                 }
3555
3556                 if(block_data_inexistent)
3557                 {
3558
3559                         if (load_if_inexistent) {
3560                                 ServerMap *svrmap = (ServerMap *)m_map;
3561                                 block = svrmap->emergeBlock(p, false);
3562                                 if (block == NULL)
3563                                         block = svrmap->createBlock(p);
3564                                 block->copyTo(*this);
3565                         } else {
3566                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
3567
3568                                 /*
3569                                         Mark area inexistent
3570                                 */
3571                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3572                                 // Fill with VOXELFLAG_NO_DATA
3573                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3574                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3575                                 {
3576                                         s32 i = m_area.index(a.MinEdge.X,y,z);
3577                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
3578                                 }
3579                         }
3580                 }
3581                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3582                 {
3583                         // Mark that block was loaded as blank
3584                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3585                 }*/
3586
3587                 m_loaded_blocks[p] = flags;
3588         }
3589
3590         m_is_dirty = false;
3591 }
3592
3593 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
3594         bool overwrite_generated)
3595 {
3596         if(m_area.getExtent() == v3s16(0,0,0))
3597                 return;
3598
3599         /*
3600                 Copy data of all blocks
3601         */
3602         for(std::map<v3s16, u8>::iterator
3603                         i = m_loaded_blocks.begin();
3604                         i != m_loaded_blocks.end(); ++i)
3605         {
3606                 v3s16 p = i->first;
3607                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3608                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
3609                 if ((existed == false) || (block == NULL) ||
3610                         (overwrite_generated == false && block->isGenerated() == true))
3611                         continue;
3612
3613                 block->copyFrom(*this);
3614
3615                 if(modified_blocks)
3616                         (*modified_blocks)[p] = block;
3617         }
3618 }
3619
3620 //END