Tolerate packet reordering in the early init process
[oweals/minetest.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         return t;
2091 }
2092
2093 void Map::setNodeTimer(v3s16 p, NodeTimer t)
2094 {
2095         v3s16 blockpos = getNodeBlockPos(p);
2096         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2097         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2098         if(!block){
2099                 infostream<<"Map::setNodeTimer(): Need to emerge "
2100                                 <<PP(blockpos)<<std::endl;
2101                 block = emergeBlock(blockpos, false);
2102         }
2103         if(!block){
2104                 warningstream<<"Map::setNodeTimer(): Block not found"
2105                                 <<std::endl;
2106                 return;
2107         }
2108         block->m_node_timers.set(p_rel, t);
2109 }
2110
2111 void Map::removeNodeTimer(v3s16 p)
2112 {
2113         v3s16 blockpos = getNodeBlockPos(p);
2114         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2115         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2116         if(block == NULL)
2117         {
2118                 warningstream<<"Map::removeNodeTimer(): Block not found"
2119                                 <<std::endl;
2120                 return;
2121         }
2122         block->m_node_timers.remove(p_rel);
2123 }
2124
2125 /*
2126         ServerMap
2127 */
2128 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2129         Map(dout_server, gamedef),
2130         m_emerge(emerge),
2131         m_map_metadata_changed(true)
2132 {
2133         verbosestream<<FUNCTION_NAME<<std::endl;
2134
2135         /*
2136                 Try to load map; if not found, create a new one.
2137         */
2138
2139         // Determine which database backend to use
2140         std::string conf_path = savedir + DIR_DELIM + "world.mt";
2141         Settings conf;
2142         bool succeeded = conf.readConfigFile(conf_path.c_str());
2143         if (!succeeded || !conf.exists("backend")) {
2144                 // fall back to sqlite3
2145                 conf.set("backend", "sqlite3");
2146         }
2147         std::string backend = conf.get("backend");
2148         dbase = createDatabase(backend, savedir, conf);
2149
2150         if (!conf.updateConfigFile(conf_path.c_str()))
2151                 errorstream << "ServerMap::ServerMap(): Failed to update world.mt!" << std::endl;
2152
2153         m_savedir = savedir;
2154         m_map_saving_enabled = false;
2155
2156         try
2157         {
2158                 // If directory exists, check contents and load if possible
2159                 if(fs::PathExists(m_savedir))
2160                 {
2161                         // If directory is empty, it is safe to save into it.
2162                         if(fs::GetDirListing(m_savedir).size() == 0)
2163                         {
2164                                 infostream<<"ServerMap: Empty save directory is valid."
2165                                                 <<std::endl;
2166                                 m_map_saving_enabled = true;
2167                         }
2168                         else
2169                         {
2170                                 try{
2171                                         // Load map metadata (seed, chunksize)
2172                                         loadMapMeta();
2173                                 }
2174                                 catch(SettingNotFoundException &e){
2175                                         infostream<<"ServerMap:  Some metadata not found."
2176                                                           <<" Using default settings."<<std::endl;
2177                                 }
2178                                 catch(FileNotGoodException &e){
2179                                         warningstream<<"Could not load map metadata"
2180                                                         //<<" Disabling chunk-based generator."
2181                                                         <<std::endl;
2182                                         //m_chunksize = 0;
2183                                 }
2184
2185                                 infostream<<"ServerMap: Successfully loaded map "
2186                                                 <<"metadata from "<<savedir
2187                                                 <<", assuming valid save directory."
2188                                                 <<" seed="<< m_emerge->params.seed <<"."
2189                                                 <<std::endl;
2190
2191                                 m_map_saving_enabled = true;
2192                                 // Map loaded, not creating new one
2193                                 return;
2194                         }
2195                 }
2196                 // If directory doesn't exist, it is safe to save to it
2197                 else{
2198                         m_map_saving_enabled = true;
2199                 }
2200         }
2201         catch(std::exception &e)
2202         {
2203                 warningstream<<"ServerMap: Failed to load map from "<<savedir
2204                                 <<", exception: "<<e.what()<<std::endl;
2205                 infostream<<"Please remove the map or fix it."<<std::endl;
2206                 warningstream<<"Map saving will be disabled."<<std::endl;
2207         }
2208
2209         infostream<<"Initializing new map."<<std::endl;
2210
2211         // Create zero sector
2212         emergeSector(v2s16(0,0));
2213
2214         // Initially write whole map
2215         save(MOD_STATE_CLEAN);
2216 }
2217
2218 ServerMap::~ServerMap()
2219 {
2220         verbosestream<<FUNCTION_NAME<<std::endl;
2221
2222         try
2223         {
2224                 if(m_map_saving_enabled)
2225                 {
2226                         // Save only changed parts
2227                         save(MOD_STATE_WRITE_AT_UNLOAD);
2228                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2229                 }
2230                 else
2231                 {
2232                         infostream<<"ServerMap: Map not saved"<<std::endl;
2233                 }
2234         }
2235         catch(std::exception &e)
2236         {
2237                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2238                                 <<", exception: "<<e.what()<<std::endl;
2239         }
2240
2241         /*
2242                 Close database if it was opened
2243         */
2244         delete dbase;
2245
2246 #if 0
2247         /*
2248                 Free all MapChunks
2249         */
2250         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2251         for(; i.atEnd() == false; i++)
2252         {
2253                 MapChunk *chunk = i.getNode()->getValue();
2254                 delete chunk;
2255         }
2256 #endif
2257 }
2258
2259 u64 ServerMap::getSeed()
2260 {
2261         return m_emerge->params.seed;
2262 }
2263
2264 s16 ServerMap::getWaterLevel()
2265 {
2266         return m_emerge->params.water_level;
2267 }
2268
2269 bool ServerMap::initBlockMake(v3s16 blockpos, BlockMakeData *data)
2270 {
2271         s16 csize = m_emerge->params.chunksize;
2272         v3s16 bpmin = EmergeManager::getContainingChunk(blockpos, csize);
2273         v3s16 bpmax = bpmin + v3s16(1, 1, 1) * (csize - 1);
2274
2275         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
2276         EMERGE_DBG_OUT("initBlockMake(): " PP(bpmin) " - " PP(bpmax));
2277
2278         v3s16 extra_borders(1, 1, 1);
2279         v3s16 full_bpmin = bpmin - extra_borders;
2280         v3s16 full_bpmax = bpmax + extra_borders;
2281
2282         // Do nothing if not inside limits (+-1 because of neighbors)
2283         if (blockpos_over_limit(full_bpmin) ||
2284                 blockpos_over_limit(full_bpmax))
2285                 return false;
2286
2287         data->seed = m_emerge->params.seed;
2288         data->blockpos_min = bpmin;
2289         data->blockpos_max = bpmax;
2290         data->blockpos_requested = blockpos;
2291         data->nodedef = m_gamedef->ndef();
2292
2293         /*
2294                 Create the whole area of this and the neighboring blocks
2295         */
2296         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
2297         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++) {
2298                 v2s16 sectorpos(x, z);
2299                 // Sector metadata is loaded from disk if not already loaded.
2300                 ServerMapSector *sector = createSector(sectorpos);
2301                 FATAL_ERROR_IF(sector == NULL, "createSector() failed");
2302
2303                 for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
2304                         v3s16 p(x, y, z);
2305
2306                         MapBlock *block = emergeBlock(p, false);
2307                         if (block == NULL) {
2308                                 block = createBlock(p);
2309
2310                                 // Block gets sunlight if this is true.
2311                                 // Refer to the map generator heuristics.
2312                                 bool ug = m_emerge->isBlockUnderground(p);
2313                                 block->setIsUnderground(ug);
2314                         }
2315                 }
2316         }
2317
2318         /*
2319                 Now we have a big empty area.
2320
2321                 Make a ManualMapVoxelManipulator that contains this and the
2322                 neighboring blocks
2323         */
2324
2325         data->vmanip = new MMVManip(this);
2326         data->vmanip->initialEmerge(full_bpmin, full_bpmax);
2327
2328         // Note: we may need this again at some point.
2329 #if 0
2330         // Ensure none of the blocks to be generated were marked as
2331         // containing CONTENT_IGNORE
2332         for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2333                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2334                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2335                                 core::map<v3s16, u8>::Node *n;
2336                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2337                                 if (n == NULL)
2338                                         continue;
2339                                 u8 flags = n->getValue();
2340                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2341                                 n->setValue(flags);
2342                         }
2343                 }
2344         }
2345 #endif
2346
2347         // Data is ready now.
2348         return true;
2349 }
2350
2351 void ServerMap::finishBlockMake(BlockMakeData *data,
2352         std::map<v3s16, MapBlock*> *changed_blocks)
2353 {
2354         v3s16 bpmin = data->blockpos_min;
2355         v3s16 bpmax = data->blockpos_max;
2356
2357         v3s16 extra_borders(1, 1, 1);
2358         v3s16 full_bpmin = bpmin - extra_borders;
2359         v3s16 full_bpmax = bpmax + extra_borders;
2360
2361         bool enable_mapgen_debug_info = m_emerge->enable_mapgen_debug_info;
2362         EMERGE_DBG_OUT("finishBlockMake(): " PP(bpmin) " - " PP(bpmax));
2363
2364         /*
2365                 Set lighting to non-expired state in all of them.
2366                 This is cheating, but it is not fast enough if all of them
2367                 would actually be updated.
2368         */
2369         for (s16 x = full_bpmin.X; x <= full_bpmax.X; x++)
2370         for (s16 z = full_bpmin.Z; z <= full_bpmax.Z; z++)
2371         for (s16 y = full_bpmin.Y; y <= full_bpmax.Y; y++) {
2372                 MapBlock *block = emergeBlock(v3s16(x, y, z), false);
2373                 if (!block)
2374                         continue;
2375
2376                 block->setLightingExpired(false);
2377         }
2378
2379         /*
2380                 Blit generated stuff to map
2381                 NOTE: blitBackAll adds nearly everything to changed_blocks
2382         */
2383         data->vmanip->blitBackAll(changed_blocks);
2384
2385         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()="
2386                 << changed_blocks->size());
2387
2388         /*
2389                 Copy transforming liquid information
2390         */
2391         while (data->transforming_liquid.size()) {
2392                 m_transforming_liquid.push_back(data->transforming_liquid.front());
2393                 data->transforming_liquid.pop_front();
2394         }
2395
2396         for (std::map<v3s16, MapBlock *>::iterator
2397                         it = changed_blocks->begin();
2398                         it != changed_blocks->end(); ++it) {
2399                 MapBlock *block = it->second;
2400                 if (!block)
2401                         continue;
2402                 /*
2403                         Update day/night difference cache of the MapBlocks
2404                 */
2405                 block->expireDayNightDiff();
2406                 /*
2407                         Set block as modified
2408                 */
2409                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2410                         MOD_REASON_EXPIRE_DAYNIGHTDIFF);
2411         }
2412
2413         /*
2414                 Set central blocks as generated
2415         */
2416         for (s16 x = bpmin.X; x <= bpmax.X; x++)
2417         for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
2418         for (s16 y = bpmin.Y; y <= bpmax.Y; y++) {
2419                 MapBlock *block = getBlockNoCreateNoEx(v3s16(x, y, z));
2420                 if (!block)
2421                         continue;
2422
2423                 block->setGenerated(true);
2424         }
2425
2426         /*
2427                 Save changed parts of map
2428                 NOTE: Will be saved later.
2429         */
2430         //save(MOD_STATE_WRITE_AT_UNLOAD);
2431 }
2432
2433 ServerMapSector *ServerMap::createSector(v2s16 p2d)
2434 {
2435         DSTACKF("%s: p2d=(%d,%d)",
2436                         FUNCTION_NAME,
2437                         p2d.X, p2d.Y);
2438
2439         /*
2440                 Check if it exists already in memory
2441         */
2442         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2443         if(sector != NULL)
2444                 return sector;
2445
2446         /*
2447                 Try to load it from disk (with blocks)
2448         */
2449         //if(loadSectorFull(p2d) == true)
2450
2451         /*
2452                 Try to load metadata from disk
2453         */
2454 #if 0
2455         if(loadSectorMeta(p2d) == true)
2456         {
2457                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2458                 if(sector == NULL)
2459                 {
2460                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2461                         throw InvalidPositionException("");
2462                 }
2463                 return sector;
2464         }
2465 #endif
2466         /*
2467                 Do not create over-limit
2468         */
2469         const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
2470                 g_settings->getU16("map_generation_limit"));
2471         if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
2472                         || p2d.X >  map_gen_limit / MAP_BLOCKSIZE
2473                         || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
2474                         || p2d.Y >  map_gen_limit / MAP_BLOCKSIZE)
2475                 throw InvalidPositionException("createSector(): pos. over limit");
2476
2477         /*
2478                 Generate blank sector
2479         */
2480
2481         sector = new ServerMapSector(this, p2d, m_gamedef);
2482
2483         // Sector position on map in nodes
2484         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2485
2486         /*
2487                 Insert to container
2488         */
2489         m_sectors[p2d] = sector;
2490
2491         return sector;
2492 }
2493
2494 #if 0
2495 /*
2496         This is a quick-hand function for calling makeBlock().
2497 */
2498 MapBlock * ServerMap::generateBlock(
2499                 v3s16 p,
2500                 std::map<v3s16, MapBlock*> &modified_blocks
2501 )
2502 {
2503         DSTACKF("%s: p=(%d,%d,%d)", FUNCTION_NAME, p.X, p.Y, p.Z);
2504
2505         /*infostream<<"generateBlock(): "
2506                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2507                         <<std::endl;*/
2508
2509         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2510
2511         TimeTaker timer("generateBlock");
2512
2513         //MapBlock *block = original_dummy;
2514
2515         v2s16 p2d(p.X, p.Z);
2516         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2517
2518         /*
2519                 Do not generate over-limit
2520         */
2521         if(blockpos_over_limit(p))
2522         {
2523                 infostream<<FUNCTION_NAME<<": Block position over limit"<<std::endl;
2524                 throw InvalidPositionException("generateBlock(): pos. over limit");
2525         }
2526
2527         /*
2528                 Create block make data
2529         */
2530         BlockMakeData data;
2531         initBlockMake(&data, p);
2532
2533         /*
2534                 Generate block
2535         */
2536         {
2537                 TimeTaker t("mapgen::make_block()");
2538                 mapgen->makeChunk(&data);
2539                 //mapgen::make_block(&data);
2540
2541                 if(enable_mapgen_debug_info == false)
2542                         t.stop(true); // Hide output
2543         }
2544
2545         /*
2546                 Blit data back on map, update lighting, add mobs and whatever this does
2547         */
2548         finishBlockMake(&data, modified_blocks);
2549
2550         /*
2551                 Get central block
2552         */
2553         MapBlock *block = getBlockNoCreateNoEx(p);
2554
2555 #if 0
2556         /*
2557                 Check result
2558         */
2559         if(block)
2560         {
2561                 bool erroneus_content = false;
2562                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2563                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2564                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2565                 {
2566                         v3s16 p(x0,y0,z0);
2567                         MapNode n = block->getNode(p);
2568                         if(n.getContent() == CONTENT_IGNORE)
2569                         {
2570                                 infostream<<"CONTENT_IGNORE at "
2571                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2572                                                 <<std::endl;
2573                                 erroneus_content = true;
2574                                 assert(0);
2575                         }
2576                 }
2577                 if(erroneus_content)
2578                 {
2579                         assert(0);
2580                 }
2581         }
2582 #endif
2583
2584 #if 0
2585         /*
2586                 Generate a completely empty block
2587         */
2588         if(block)
2589         {
2590                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2591                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2592                 {
2593                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2594                         {
2595                                 MapNode n;
2596                                 n.setContent(CONTENT_AIR);
2597                                 block->setNode(v3s16(x0,y0,z0), n);
2598                         }
2599                 }
2600         }
2601 #endif
2602
2603         if(enable_mapgen_debug_info == false)
2604                 timer.stop(true); // Hide output
2605
2606         return block;
2607 }
2608 #endif
2609
2610 MapBlock * ServerMap::createBlock(v3s16 p)
2611 {
2612         DSTACKF("%s: p=(%d,%d,%d)",
2613                         FUNCTION_NAME, p.X, p.Y, p.Z);
2614
2615         /*
2616                 Do not create over-limit
2617         */
2618         if (blockpos_over_limit(p))
2619                 throw InvalidPositionException("createBlock(): pos. over limit");
2620
2621         v2s16 p2d(p.X, p.Z);
2622         s16 block_y = p.Y;
2623         /*
2624                 This will create or load a sector if not found in memory.
2625                 If block exists on disk, it will be loaded.
2626
2627                 NOTE: On old save formats, this will be slow, as it generates
2628                       lighting on blocks for them.
2629         */
2630         ServerMapSector *sector;
2631         try {
2632                 sector = (ServerMapSector*)createSector(p2d);
2633                 assert(sector->getId() == MAPSECTOR_SERVER);
2634         }
2635         catch(InvalidPositionException &e)
2636         {
2637                 infostream<<"createBlock: createSector() failed"<<std::endl;
2638                 throw e;
2639         }
2640         /*
2641                 NOTE: This should not be done, or at least the exception
2642                 should not be passed on as std::exception, because it
2643                 won't be catched at all.
2644         */
2645         /*catch(std::exception &e)
2646         {
2647                 infostream<<"createBlock: createSector() failed: "
2648                                 <<e.what()<<std::endl;
2649                 throw e;
2650         }*/
2651
2652         /*
2653                 Try to get a block from the sector
2654         */
2655
2656         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2657         if(block)
2658         {
2659                 if(block->isDummy())
2660                         block->unDummify();
2661                 return block;
2662         }
2663         // Create blank
2664         block = sector->createBlankBlock(block_y);
2665
2666         return block;
2667 }
2668
2669 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2670 {
2671         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2672                         FUNCTION_NAME,
2673                         p.X, p.Y, p.Z, create_blank);
2674
2675         {
2676                 MapBlock *block = getBlockNoCreateNoEx(p);
2677                 if(block && block->isDummy() == false)
2678                         return block;
2679         }
2680
2681         {
2682                 MapBlock *block = loadBlock(p);
2683                 if(block)
2684                         return block;
2685         }
2686
2687         if (create_blank) {
2688                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2689                 MapBlock *block = sector->createBlankBlock(p.Y);
2690
2691                 return block;
2692         }
2693
2694 #if 0
2695         if(allow_generate)
2696         {
2697                 std::map<v3s16, MapBlock*> modified_blocks;
2698                 MapBlock *block = generateBlock(p, modified_blocks);
2699                 if(block)
2700                 {
2701                         MapEditEvent event;
2702                         event.type = MEET_OTHER;
2703                         event.p = p;
2704
2705                         // Copy modified_blocks to event
2706                         for(std::map<v3s16, MapBlock*>::iterator
2707                                         i = modified_blocks.begin();
2708                                         i != modified_blocks.end(); ++i)
2709                         {
2710                                 event.modified_blocks.insert(i->first);
2711                         }
2712
2713                         // Queue event
2714                         dispatchEvent(&event);
2715
2716                         return block;
2717                 }
2718         }
2719 #endif
2720
2721         return NULL;
2722 }
2723
2724 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
2725 {
2726         MapBlock *block = getBlockNoCreateNoEx(p3d);
2727         if (block == NULL)
2728                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
2729
2730         return block;
2731 }
2732
2733 void ServerMap::prepareBlock(MapBlock *block) {
2734 }
2735
2736 // N.B.  This requires no synchronization, since data will not be modified unless
2737 // the VoxelManipulator being updated belongs to the same thread.
2738 void ServerMap::updateVManip(v3s16 pos)
2739 {
2740         Mapgen *mg = m_emerge->getCurrentMapgen();
2741         if (!mg)
2742                 return;
2743
2744         MMVManip *vm = mg->vm;
2745         if (!vm)
2746                 return;
2747
2748         if (!vm->m_area.contains(pos))
2749                 return;
2750
2751         s32 idx = vm->m_area.index(pos);
2752         vm->m_data[idx] = getNodeNoEx(pos);
2753         vm->m_flags[idx] &= ~VOXELFLAG_NO_DATA;
2754
2755         vm->m_is_dirty = true;
2756 }
2757
2758 s16 ServerMap::findGroundLevel(v2s16 p2d)
2759 {
2760 #if 0
2761         /*
2762                 Uh, just do something random...
2763         */
2764         // Find existing map from top to down
2765         s16 max=63;
2766         s16 min=-64;
2767         v3s16 p(p2d.X, max, p2d.Y);
2768         for(; p.Y>min; p.Y--)
2769         {
2770                 MapNode n = getNodeNoEx(p);
2771                 if(n.getContent() != CONTENT_IGNORE)
2772                         break;
2773         }
2774         if(p.Y == min)
2775                 goto plan_b;
2776         // If this node is not air, go to plan b
2777         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2778                 goto plan_b;
2779         // Search existing walkable and return it
2780         for(; p.Y>min; p.Y--)
2781         {
2782                 MapNode n = getNodeNoEx(p);
2783                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2784                         return p.Y;
2785         }
2786
2787         // Move to plan b
2788 plan_b:
2789 #endif
2790
2791         /*
2792                 Determine from map generator noise functions
2793         */
2794
2795         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2796         return level;
2797
2798         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2799         //return (s16)level;
2800 }
2801
2802 bool ServerMap::loadFromFolders() {
2803         if (!dbase->initialized() &&
2804                         !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2805                 return true;
2806         return false;
2807 }
2808
2809 void ServerMap::createDirs(std::string path)
2810 {
2811         if(fs::CreateAllDirs(path) == false)
2812         {
2813                 m_dout<<"ServerMap: Failed to create directory "
2814                                 <<"\""<<path<<"\""<<std::endl;
2815                 throw BaseException("ServerMap failed to create directory");
2816         }
2817 }
2818
2819 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2820 {
2821         char cc[9];
2822         switch(layout)
2823         {
2824                 case 1:
2825                         snprintf(cc, 9, "%.4x%.4x",
2826                                 (unsigned int) pos.X & 0xffff,
2827                                 (unsigned int) pos.Y & 0xffff);
2828
2829                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2830                 case 2:
2831                         snprintf(cc, 9, (std::string("%.3x") + DIR_DELIM + "%.3x").c_str(),
2832                                 (unsigned int) pos.X & 0xfff,
2833                                 (unsigned int) pos.Y & 0xfff);
2834
2835                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2836                 default:
2837                         assert(false);
2838                         return "";
2839         }
2840 }
2841
2842 v2s16 ServerMap::getSectorPos(std::string dirname)
2843 {
2844         unsigned int x = 0, y = 0;
2845         int r;
2846         std::string component;
2847         fs::RemoveLastPathComponent(dirname, &component, 1);
2848         if(component.size() == 8)
2849         {
2850                 // Old layout
2851                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
2852         }
2853         else if(component.size() == 3)
2854         {
2855                 // New layout
2856                 fs::RemoveLastPathComponent(dirname, &component, 2);
2857                 r = sscanf(component.c_str(), (std::string("%3x") + DIR_DELIM + "%3x").c_str(), &x, &y);
2858                 // Sign-extend the 12 bit values up to 16 bits...
2859                 if(x & 0x800) x |= 0xF000;
2860                 if(y & 0x800) y |= 0xF000;
2861         }
2862         else
2863         {
2864                 r = -1;
2865         }
2866
2867         FATAL_ERROR_IF(r != 2, "getSectorPos()");
2868         v2s16 pos((s16)x, (s16)y);
2869         return pos;
2870 }
2871
2872 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2873 {
2874         v2s16 p2d = getSectorPos(sectordir);
2875
2876         if(blockfile.size() != 4){
2877                 throw InvalidFilenameException("Invalid block filename");
2878         }
2879         unsigned int y;
2880         int r = sscanf(blockfile.c_str(), "%4x", &y);
2881         if(r != 1)
2882                 throw InvalidFilenameException("Invalid block filename");
2883         return v3s16(p2d.X, y, p2d.Y);
2884 }
2885
2886 std::string ServerMap::getBlockFilename(v3s16 p)
2887 {
2888         char cc[5];
2889         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2890         return cc;
2891 }
2892
2893 void ServerMap::save(ModifiedState save_level)
2894 {
2895         DSTACK(FUNCTION_NAME);
2896         if(m_map_saving_enabled == false) {
2897                 warningstream<<"Not saving map, saving disabled."<<std::endl;
2898                 return;
2899         }
2900
2901         if(save_level == MOD_STATE_CLEAN)
2902                 infostream<<"ServerMap: Saving whole map, this can take time."
2903                                 <<std::endl;
2904
2905         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN) {
2906                 saveMapMeta();
2907         }
2908
2909         // Profile modified reasons
2910         Profiler modprofiler;
2911
2912         u32 sector_meta_count = 0;
2913         u32 block_count = 0;
2914         u32 block_count_all = 0; // Number of blocks in memory
2915
2916         // Don't do anything with sqlite unless something is really saved
2917         bool save_started = false;
2918
2919         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
2920                 i != m_sectors.end(); ++i) {
2921                 ServerMapSector *sector = (ServerMapSector*)i->second;
2922                 assert(sector->getId() == MAPSECTOR_SERVER);
2923
2924                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN) {
2925                         saveSectorMeta(sector);
2926                         sector_meta_count++;
2927                 }
2928
2929                 MapBlockVect blocks;
2930                 sector->getBlocks(blocks);
2931
2932                 for(MapBlockVect::iterator j = blocks.begin();
2933                         j != blocks.end(); ++j) {
2934                         MapBlock *block = *j;
2935
2936                         block_count_all++;
2937
2938                         if(block->getModified() >= (u32)save_level) {
2939                                 // Lazy beginSave()
2940                                 if(!save_started) {
2941                                         beginSave();
2942                                         save_started = true;
2943                                 }
2944
2945                                 modprofiler.add(block->getModifiedReasonString(), 1);
2946
2947                                 saveBlock(block);
2948                                 block_count++;
2949
2950                                 /*infostream<<"ServerMap: Written block ("
2951                                                 <<block->getPos().X<<","
2952                                                 <<block->getPos().Y<<","
2953                                                 <<block->getPos().Z<<")"
2954                                                 <<std::endl;*/
2955                         }
2956                 }
2957         }
2958
2959         if(save_started)
2960                 endSave();
2961
2962         /*
2963                 Only print if something happened or saved whole map
2964         */
2965         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
2966                         || block_count != 0) {
2967                 infostream<<"ServerMap: Written: "
2968                                 <<sector_meta_count<<" sector metadata files, "
2969                                 <<block_count<<" block files"
2970                                 <<", "<<block_count_all<<" blocks in memory."
2971                                 <<std::endl;
2972                 PrintInfo(infostream); // ServerMap/ClientMap:
2973                 infostream<<"Blocks modified by: "<<std::endl;
2974                 modprofiler.print(infostream);
2975         }
2976 }
2977
2978 void ServerMap::listAllLoadableBlocks(std::vector<v3s16> &dst)
2979 {
2980         if (loadFromFolders()) {
2981                 errorstream << "Map::listAllLoadableBlocks(): Result will be missing "
2982                                 << "all blocks that are stored in flat files." << std::endl;
2983         }
2984         dbase->listAllLoadableBlocks(dst);
2985 }
2986
2987 void ServerMap::listAllLoadedBlocks(std::vector<v3s16> &dst)
2988 {
2989         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
2990                 si != m_sectors.end(); ++si)
2991         {
2992                 MapSector *sector = si->second;
2993
2994                 MapBlockVect blocks;
2995                 sector->getBlocks(blocks);
2996
2997                 for(MapBlockVect::iterator i = blocks.begin();
2998                                 i != blocks.end(); ++i) {
2999                         v3s16 p = (*i)->getPos();
3000                         dst.push_back(p);
3001                 }
3002         }
3003 }
3004
3005 void ServerMap::saveMapMeta()
3006 {
3007         DSTACK(FUNCTION_NAME);
3008
3009         createDirs(m_savedir);
3010
3011         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3012         std::ostringstream oss(std::ios_base::binary);
3013         Settings conf;
3014
3015         m_emerge->params.save(conf);
3016         conf.writeLines(oss);
3017
3018         oss << "[end_of_params]\n";
3019
3020         if(!fs::safeWriteToFile(fullpath, oss.str())) {
3021                 errorstream << "ServerMap::saveMapMeta(): "
3022                                 << "could not write " << fullpath << std::endl;
3023                 throw FileNotGoodException("Cannot save chunk metadata");
3024         }
3025
3026         m_map_metadata_changed = false;
3027 }
3028
3029 void ServerMap::loadMapMeta()
3030 {
3031         DSTACK(FUNCTION_NAME);
3032
3033         Settings conf;
3034         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3035
3036         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3037         if (!is.good()) {
3038                 errorstream << "ServerMap::loadMapMeta(): "
3039                         "could not open " << fullpath << std::endl;
3040                 throw FileNotGoodException("Cannot open map metadata");
3041         }
3042
3043         if (!conf.parseConfigLines(is, "[end_of_params]")) {
3044                 throw SerializationError("ServerMap::loadMapMeta(): "
3045                                 "[end_of_params] not found!");
3046         }
3047
3048         m_emerge->params.load(conf);
3049
3050         verbosestream << "ServerMap::loadMapMeta(): seed="
3051                 << m_emerge->params.seed << std::endl;
3052 }
3053
3054 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3055 {
3056         DSTACK(FUNCTION_NAME);
3057         // Format used for writing
3058         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3059         // Get destination
3060         v2s16 pos = sector->getPos();
3061         std::string dir = getSectorDir(pos);
3062         createDirs(dir);
3063
3064         std::string fullpath = dir + DIR_DELIM + "meta";
3065         std::ostringstream ss(std::ios_base::binary);
3066
3067         sector->serialize(ss, version);
3068
3069         if(!fs::safeWriteToFile(fullpath, ss.str()))
3070                 throw FileNotGoodException("Cannot write sector metafile");
3071
3072         sector->differs_from_disk = false;
3073 }
3074
3075 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3076 {
3077         DSTACK(FUNCTION_NAME);
3078         // Get destination
3079         v2s16 p2d = getSectorPos(sectordir);
3080
3081         ServerMapSector *sector = NULL;
3082
3083         std::string fullpath = sectordir + DIR_DELIM + "meta";
3084         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3085         if(is.good() == false)
3086         {
3087                 // If the directory exists anyway, it probably is in some old
3088                 // format. Just go ahead and create the sector.
3089                 if(fs::PathExists(sectordir))
3090                 {
3091                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3092                                         <<fullpath<<" doesn't exist but directory does."
3093                                         <<" Continuing with a sector with no metadata."
3094                                         <<std::endl;*/
3095                         sector = new ServerMapSector(this, p2d, m_gamedef);
3096                         m_sectors[p2d] = sector;
3097                 }
3098                 else
3099                 {
3100                         throw FileNotGoodException("Cannot open sector metafile");
3101                 }
3102         }
3103         else
3104         {
3105                 sector = ServerMapSector::deSerialize
3106                                 (is, this, p2d, m_sectors, m_gamedef);
3107                 if(save_after_load)
3108                         saveSectorMeta(sector);
3109         }
3110
3111         sector->differs_from_disk = false;
3112
3113         return sector;
3114 }
3115
3116 bool ServerMap::loadSectorMeta(v2s16 p2d)
3117 {
3118         DSTACK(FUNCTION_NAME);
3119
3120         // The directory layout we're going to load from.
3121         //  1 - original sectors/xxxxzzzz/
3122         //  2 - new sectors2/xxx/zzz/
3123         //  If we load from anything but the latest structure, we will
3124         //  immediately save to the new one, and remove the old.
3125         int loadlayout = 1;
3126         std::string sectordir1 = getSectorDir(p2d, 1);
3127         std::string sectordir;
3128         if(fs::PathExists(sectordir1))
3129         {
3130                 sectordir = sectordir1;
3131         }
3132         else
3133         {
3134                 loadlayout = 2;
3135                 sectordir = getSectorDir(p2d, 2);
3136         }
3137
3138         try{
3139                 loadSectorMeta(sectordir, loadlayout != 2);
3140         }
3141         catch(InvalidFilenameException &e)
3142         {
3143                 return false;
3144         }
3145         catch(FileNotGoodException &e)
3146         {
3147                 return false;
3148         }
3149         catch(std::exception &e)
3150         {
3151                 return false;
3152         }
3153
3154         return true;
3155 }
3156
3157 #if 0
3158 bool ServerMap::loadSectorFull(v2s16 p2d)
3159 {
3160         DSTACK(FUNCTION_NAME);
3161
3162         MapSector *sector = NULL;
3163
3164         // The directory layout we're going to load from.
3165         //  1 - original sectors/xxxxzzzz/
3166         //  2 - new sectors2/xxx/zzz/
3167         //  If we load from anything but the latest structure, we will
3168         //  immediately save to the new one, and remove the old.
3169         int loadlayout = 1;
3170         std::string sectordir1 = getSectorDir(p2d, 1);
3171         std::string sectordir;
3172         if(fs::PathExists(sectordir1))
3173         {
3174                 sectordir = sectordir1;
3175         }
3176         else
3177         {
3178                 loadlayout = 2;
3179                 sectordir = getSectorDir(p2d, 2);
3180         }
3181
3182         try{
3183                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3184         }
3185         catch(InvalidFilenameException &e)
3186         {
3187                 return false;
3188         }
3189         catch(FileNotGoodException &e)
3190         {
3191                 return false;
3192         }
3193         catch(std::exception &e)
3194         {
3195                 return false;
3196         }
3197
3198         /*
3199                 Load blocks
3200         */
3201         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3202                         (sectordir);
3203         std::vector<fs::DirListNode>::iterator i2;
3204         for(i2=list2.begin(); i2!=list2.end(); i2++)
3205         {
3206                 // We want files
3207                 if(i2->dir)
3208                         continue;
3209                 try{
3210                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3211                 }
3212                 catch(InvalidFilenameException &e)
3213                 {
3214                         // This catches unknown crap in directory
3215                 }
3216         }
3217
3218         if(loadlayout != 2)
3219         {
3220                 infostream<<"Sector converted to new layout - deleting "<<
3221                         sectordir1<<std::endl;
3222                 fs::RecursiveDelete(sectordir1);
3223         }
3224
3225         return true;
3226 }
3227 #endif
3228
3229 Database *ServerMap::createDatabase(
3230         const std::string &name,
3231         const std::string &savedir,
3232         Settings &conf)
3233 {
3234         if (name == "sqlite3")
3235                 return new Database_SQLite3(savedir);
3236         if (name == "dummy")
3237                 return new Database_Dummy();
3238         #if USE_LEVELDB
3239         else if (name == "leveldb")
3240                 return new Database_LevelDB(savedir);
3241         #endif
3242         #if USE_REDIS
3243         else if (name == "redis")
3244                 return new Database_Redis(conf);
3245         #endif
3246         #if USE_POSTGRESQL
3247         else if (name == "postgresql")
3248                 return new Database_PostgreSQL(conf);
3249         #endif
3250         else
3251                 throw BaseException(std::string("Database backend ") + name + " not supported.");
3252 }
3253
3254 void ServerMap::beginSave()
3255 {
3256         dbase->beginSave();
3257 }
3258
3259 void ServerMap::endSave()
3260 {
3261         dbase->endSave();
3262 }
3263
3264 bool ServerMap::saveBlock(MapBlock *block)
3265 {
3266         return saveBlock(block, dbase);
3267 }
3268
3269 bool ServerMap::saveBlock(MapBlock *block, Database *db)
3270 {
3271         v3s16 p3d = block->getPos();
3272
3273         // Dummy blocks are not written
3274         if (block->isDummy()) {
3275                 warningstream << "saveBlock: Not writing dummy block "
3276                         << PP(p3d) << std::endl;
3277                 return true;
3278         }
3279
3280         // Format used for writing
3281         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3282
3283         /*
3284                 [0] u8 serialization version
3285                 [1] data
3286         */
3287         std::ostringstream o(std::ios_base::binary);
3288         o.write((char*) &version, 1);
3289         block->serialize(o, version, true);
3290
3291         std::string data = o.str();
3292         bool ret = db->saveBlock(p3d, data);
3293         if (ret) {
3294                 // We just wrote it to the disk so clear modified flag
3295                 block->resetModified();
3296         }
3297         return ret;
3298 }
3299
3300 void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
3301                 MapSector *sector, bool save_after_load)
3302 {
3303         DSTACK(FUNCTION_NAME);
3304
3305         std::string fullpath = sectordir + DIR_DELIM + blockfile;
3306         try {
3307
3308                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3309                 if(is.good() == false)
3310                         throw FileNotGoodException("Cannot open block file");
3311
3312                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3313                 v2s16 p2d(p3d.X, p3d.Z);
3314
3315                 assert(sector->getPos() == p2d);
3316
3317                 u8 version = SER_FMT_VER_INVALID;
3318                 is.read((char*)&version, 1);
3319
3320                 if(is.fail())
3321                         throw SerializationError("ServerMap::loadBlock(): Failed"
3322                                         " to read MapBlock version");
3323
3324                 /*u32 block_size = MapBlock::serializedLength(version);
3325                 SharedBuffer<u8> data(block_size);
3326                 is.read((char*)*data, block_size);*/
3327
3328                 // This will always return a sector because we're the server
3329                 //MapSector *sector = emergeSector(p2d);
3330
3331                 MapBlock *block = NULL;
3332                 bool created_new = false;
3333                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3334                 if(block == NULL)
3335                 {
3336                         block = sector->createBlankBlockNoInsert(p3d.Y);
3337                         created_new = true;
3338                 }
3339
3340                 // Read basic data
3341                 block->deSerialize(is, version, true);
3342
3343                 // If it's a new block, insert it to the map
3344                 if(created_new)
3345                         sector->insertBlock(block);
3346
3347                 /*
3348                         Save blocks loaded in old format in new format
3349                 */
3350
3351                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3352                 {
3353                         saveBlock(block);
3354
3355                         // Should be in database now, so delete the old file
3356                         fs::RecursiveDelete(fullpath);
3357                 }
3358
3359                 // We just loaded it from the disk, so it's up-to-date.
3360                 block->resetModified();
3361
3362         }
3363         catch(SerializationError &e)
3364         {
3365                 warningstream<<"Invalid block data on disk "
3366                                 <<"fullpath="<<fullpath
3367                                 <<" (SerializationError). "
3368                                 <<"what()="<<e.what()
3369                                 <<std::endl;
3370                                 // Ignoring. A new one will be generated.
3371                 abort();
3372
3373                 // TODO: Backup file; name is in fullpath.
3374         }
3375 }
3376
3377 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3378 {
3379         DSTACK(FUNCTION_NAME);
3380
3381         try {
3382                 std::istringstream is(*blob, std::ios_base::binary);
3383
3384                 u8 version = SER_FMT_VER_INVALID;
3385                 is.read((char*)&version, 1);
3386
3387                 if(is.fail())
3388                         throw SerializationError("ServerMap::loadBlock(): Failed"
3389                                         " to read MapBlock version");
3390
3391                 /*u32 block_size = MapBlock::serializedLength(version);
3392                 SharedBuffer<u8> data(block_size);
3393                 is.read((char*)*data, block_size);*/
3394
3395                 // This will always return a sector because we're the server
3396                 //MapSector *sector = emergeSector(p2d);
3397
3398                 MapBlock *block = NULL;
3399                 bool created_new = false;
3400                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3401                 if(block == NULL)
3402                 {
3403                         block = sector->createBlankBlockNoInsert(p3d.Y);
3404                         created_new = true;
3405                 }
3406
3407                 // Read basic data
3408                 block->deSerialize(is, version, true);
3409
3410                 // If it's a new block, insert it to the map
3411                 if(created_new)
3412                         sector->insertBlock(block);
3413
3414                 /*
3415                         Save blocks loaded in old format in new format
3416                 */
3417
3418                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3419                 // Only save if asked to; no need to update version
3420                 if(save_after_load)
3421                         saveBlock(block);
3422
3423                 // We just loaded it from, so it's up-to-date.
3424                 block->resetModified();
3425
3426         }
3427         catch(SerializationError &e)
3428         {
3429                 errorstream<<"Invalid block data in database"
3430                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3431                                 <<" (SerializationError): "<<e.what()<<std::endl;
3432
3433                 // TODO: Block should be marked as invalid in memory so that it is
3434                 // not touched but the game can run
3435
3436                 if(g_settings->getBool("ignore_world_load_errors")){
3437                         errorstream<<"Ignoring block load error. Duck and cover! "
3438                                         <<"(ignore_world_load_errors)"<<std::endl;
3439                 } else {
3440                         throw SerializationError("Invalid block data in database");
3441                 }
3442         }
3443 }
3444
3445 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3446 {
3447         DSTACK(FUNCTION_NAME);
3448
3449         v2s16 p2d(blockpos.X, blockpos.Z);
3450
3451         std::string ret;
3452         dbase->loadBlock(blockpos, &ret);
3453         if (ret != "") {
3454                 loadBlock(&ret, blockpos, createSector(p2d), false);
3455                 return getBlockNoCreateNoEx(blockpos);
3456         }
3457         // Not found in database, try the files
3458
3459         // The directory layout we're going to load from.
3460         //  1 - original sectors/xxxxzzzz/
3461         //  2 - new sectors2/xxx/zzz/
3462         //  If we load from anything but the latest structure, we will
3463         //  immediately save to the new one, and remove the old.
3464         int loadlayout = 1;
3465         std::string sectordir1 = getSectorDir(p2d, 1);
3466         std::string sectordir;
3467         if(fs::PathExists(sectordir1))
3468         {
3469                 sectordir = sectordir1;
3470         }
3471         else
3472         {
3473                 loadlayout = 2;
3474                 sectordir = getSectorDir(p2d, 2);
3475         }
3476
3477         /*
3478                 Make sure sector is loaded
3479         */
3480
3481         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3482         if(sector == NULL)
3483         {
3484                 try{
3485                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3486                 }
3487                 catch(InvalidFilenameException &e)
3488                 {
3489                         return NULL;
3490                 }
3491                 catch(FileNotGoodException &e)
3492                 {
3493                         return NULL;
3494                 }
3495                 catch(std::exception &e)
3496                 {
3497                         return NULL;
3498                 }
3499         }
3500
3501         /*
3502                 Make sure file exists
3503         */
3504
3505         std::string blockfilename = getBlockFilename(blockpos);
3506         if(fs::PathExists(sectordir + DIR_DELIM + blockfilename) == false)
3507                 return NULL;
3508
3509         /*
3510                 Load block and save it to the database
3511         */
3512         loadBlock(sectordir, blockfilename, sector, true);
3513         return getBlockNoCreateNoEx(blockpos);
3514 }
3515
3516 bool ServerMap::deleteBlock(v3s16 blockpos)
3517 {
3518         if (!dbase->deleteBlock(blockpos))
3519                 return false;
3520
3521         MapBlock *block = getBlockNoCreateNoEx(blockpos);
3522         if (block) {
3523                 v2s16 p2d(blockpos.X, blockpos.Z);
3524                 MapSector *sector = getSectorNoGenerateNoEx(p2d);
3525                 if (!sector)
3526                         return false;
3527                 sector->deleteBlock(block);
3528         }
3529
3530         return true;
3531 }
3532
3533 void ServerMap::PrintInfo(std::ostream &out)
3534 {
3535         out<<"ServerMap: ";
3536 }
3537
3538 MMVManip::MMVManip(Map *map):
3539                 VoxelManipulator(),
3540                 m_is_dirty(false),
3541                 m_create_area(false),
3542                 m_map(map)
3543 {
3544 }
3545
3546 MMVManip::~MMVManip()
3547 {
3548 }
3549
3550 void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
3551         bool load_if_inexistent)
3552 {
3553         TimeTaker timer1("initialEmerge", &emerge_time);
3554
3555         // Units of these are MapBlocks
3556         v3s16 p_min = blockpos_min;
3557         v3s16 p_max = blockpos_max;
3558
3559         VoxelArea block_area_nodes
3560                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3561
3562         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3563         if(size_MB >= 1)
3564         {
3565                 infostream<<"initialEmerge: area: ";
3566                 block_area_nodes.print(infostream);
3567                 infostream<<" ("<<size_MB<<"MB)";
3568                 infostream<<std::endl;
3569         }
3570
3571         addArea(block_area_nodes);
3572
3573         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3574         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3575         for(s32 x=p_min.X; x<=p_max.X; x++)
3576         {
3577                 u8 flags = 0;
3578                 MapBlock *block;
3579                 v3s16 p(x,y,z);
3580                 std::map<v3s16, u8>::iterator n;
3581                 n = m_loaded_blocks.find(p);
3582                 if(n != m_loaded_blocks.end())
3583                         continue;
3584
3585                 bool block_data_inexistent = false;
3586                 try
3587                 {
3588                         TimeTaker timer1("emerge load", &emerge_load_time);
3589
3590                         block = m_map->getBlockNoCreate(p);
3591                         if(block->isDummy())
3592                                 block_data_inexistent = true;
3593                         else
3594                                 block->copyTo(*this);
3595                 }
3596                 catch(InvalidPositionException &e)
3597                 {
3598                         block_data_inexistent = true;
3599                 }
3600
3601                 if(block_data_inexistent)
3602                 {
3603
3604                         if (load_if_inexistent) {
3605                                 ServerMap *svrmap = (ServerMap *)m_map;
3606                                 block = svrmap->emergeBlock(p, false);
3607                                 if (block == NULL)
3608                                         block = svrmap->createBlock(p);
3609                                 block->copyTo(*this);
3610                         } else {
3611                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
3612
3613                                 /*
3614                                         Mark area inexistent
3615                                 */
3616                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3617                                 // Fill with VOXELFLAG_NO_DATA
3618                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3619                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3620                                 {
3621                                         s32 i = m_area.index(a.MinEdge.X,y,z);
3622                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
3623                                 }
3624                         }
3625                 }
3626                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3627                 {
3628                         // Mark that block was loaded as blank
3629                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3630                 }*/
3631
3632                 m_loaded_blocks[p] = flags;
3633         }
3634
3635         m_is_dirty = false;
3636 }
3637
3638 void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
3639         bool overwrite_generated)
3640 {
3641         if(m_area.getExtent() == v3s16(0,0,0))
3642                 return;
3643
3644         /*
3645                 Copy data of all blocks
3646         */
3647         for(std::map<v3s16, u8>::iterator
3648                         i = m_loaded_blocks.begin();
3649                         i != m_loaded_blocks.end(); ++i)
3650         {
3651                 v3s16 p = i->first;
3652                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3653                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
3654                 if ((existed == false) || (block == NULL) ||
3655                         (overwrite_generated == false && block->isGenerated() == true))
3656                         continue;
3657
3658                 block->copyFrom(*this);
3659
3660                 if(modified_blocks)
3661                         (*modified_blocks)[p] = block;
3662         }
3663 }
3664
3665 //END