]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
Fix client profiler print interval
[minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 "main.h"
24 #include "client.h"
25 #include "filesys.h"
26 #include "utility.h"
27 #include "voxel.h"
28 #include "porting.h"
29 #include "mapgen.h"
30 #include "nodemetadata.h"
31 #include "content_mapnode.h"
32 #ifndef SERVER
33 #include <IMaterialRenderer.h>
34 #endif
35 #include "settings.h"
36 #include "log.h"
37 #include "profiler.h"
38
39 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
40
41 /*
42         SQLite format specification:
43         - Initially only replaces sectors/ and sectors2/
44         
45         If map.sqlite does not exist in the save dir
46         or the block was not found in the database
47         the map will try to load from sectors folder.
48         In either case, map.sqlite will be created
49         and all future saves will save there.
50         
51         Structure of map.sqlite:
52         Tables:
53                 blocks
54                         (PK) INT pos
55                         BLOB data
56 */
57
58 /*
59         Map
60 */
61
62 Map::Map(std::ostream &dout):
63         m_dout(dout),
64         m_sector_cache(NULL)
65 {
66         /*m_sector_mutex.Init();
67         assert(m_sector_mutex.IsInitialized());*/
68 }
69
70 Map::~Map()
71 {
72         /*
73                 Free all MapSectors
74         */
75         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
76         for(; i.atEnd() == false; i++)
77         {
78                 MapSector *sector = i.getNode()->getValue();
79                 delete sector;
80         }
81 }
82
83 void Map::addEventReceiver(MapEventReceiver *event_receiver)
84 {
85         m_event_receivers.insert(event_receiver, false);
86 }
87
88 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
89 {
90         if(m_event_receivers.find(event_receiver) == NULL)
91                 return;
92         m_event_receivers.remove(event_receiver);
93 }
94
95 void Map::dispatchEvent(MapEditEvent *event)
96 {
97         for(core::map<MapEventReceiver*, bool>::Iterator
98                         i = m_event_receivers.getIterator();
99                         i.atEnd()==false; i++)
100         {
101                 MapEventReceiver* event_receiver = i.getNode()->getKey();
102                 event_receiver->onMapEditEvent(event);
103         }
104 }
105
106 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
107 {
108         if(m_sector_cache != NULL && p == m_sector_cache_p){
109                 MapSector * sector = m_sector_cache;
110                 return sector;
111         }
112         
113         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p);
114         
115         if(n == NULL)
116                 return NULL;
117         
118         MapSector *sector = n->getValue();
119         
120         // Cache the last result
121         m_sector_cache_p = p;
122         m_sector_cache = sector;
123
124         return sector;
125 }
126
127 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
128 {
129         return getSectorNoGenerateNoExNoLock(p);
130 }
131
132 MapSector * Map::getSectorNoGenerate(v2s16 p)
133 {
134         MapSector *sector = getSectorNoGenerateNoEx(p);
135         if(sector == NULL)
136                 throw InvalidPositionException();
137         
138         return sector;
139 }
140
141 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
142 {
143         v2s16 p2d(p3d.X, p3d.Z);
144         MapSector * sector = getSectorNoGenerateNoEx(p2d);
145         if(sector == NULL)
146                 return NULL;
147         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
148         return block;
149 }
150
151 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
152 {       
153         MapBlock *block = getBlockNoCreateNoEx(p3d);
154         if(block == NULL)
155                 throw InvalidPositionException();
156         return block;
157 }
158
159 bool Map::isNodeUnderground(v3s16 p)
160 {
161         v3s16 blockpos = getNodeBlockPos(p);
162         try{
163                 MapBlock * block = getBlockNoCreate(blockpos);
164                 return block->getIsUnderground();
165         }
166         catch(InvalidPositionException &e)
167         {
168                 return false;
169         }
170 }
171
172 bool Map::isValidPosition(v3s16 p)
173 {
174         v3s16 blockpos = getNodeBlockPos(p);
175         MapBlock *block = getBlockNoCreate(blockpos);
176         return (block != NULL);
177 }
178
179 // Returns a CONTENT_IGNORE node if not found
180 MapNode Map::getNodeNoEx(v3s16 p)
181 {
182         v3s16 blockpos = getNodeBlockPos(p);
183         MapBlock *block = getBlockNoCreateNoEx(blockpos);
184         if(block == NULL)
185                 return MapNode(CONTENT_IGNORE);
186         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
187         return block->getNodeNoCheck(relpos);
188 }
189
190 // throws InvalidPositionException if not found
191 MapNode Map::getNode(v3s16 p)
192 {
193         v3s16 blockpos = getNodeBlockPos(p);
194         MapBlock *block = getBlockNoCreateNoEx(blockpos);
195         if(block == NULL)
196                 throw InvalidPositionException();
197         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
198         return block->getNodeNoCheck(relpos);
199 }
200
201 // throws InvalidPositionException if not found
202 void Map::setNode(v3s16 p, MapNode & n)
203 {
204         v3s16 blockpos = getNodeBlockPos(p);
205         MapBlock *block = getBlockNoCreate(blockpos);
206         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
207         block->setNodeNoCheck(relpos, n);
208 }
209
210
211 /*
212         Goes recursively through the neighbours of the node.
213
214         Alters only transparent nodes.
215
216         If the lighting of the neighbour is lower than the lighting of
217         the node was (before changing it to 0 at the step before), the
218         lighting of the neighbour is set to 0 and then the same stuff
219         repeats for the neighbour.
220
221         The ending nodes of the routine are stored in light_sources.
222         This is useful when a light is removed. In such case, this
223         routine can be called for the light node and then again for
224         light_sources to re-light the area without the removed light.
225
226         values of from_nodes are lighting values.
227 */
228 void Map::unspreadLight(enum LightBank bank,
229                 core::map<v3s16, u8> & from_nodes,
230                 core::map<v3s16, bool> & light_sources,
231                 core::map<v3s16, MapBlock*>  & modified_blocks)
232 {
233         v3s16 dirs[6] = {
234                 v3s16(0,0,1), // back
235                 v3s16(0,1,0), // top
236                 v3s16(1,0,0), // right
237                 v3s16(0,0,-1), // front
238                 v3s16(0,-1,0), // bottom
239                 v3s16(-1,0,0), // left
240         };
241         
242         if(from_nodes.size() == 0)
243                 return;
244         
245         u32 blockchangecount = 0;
246
247         core::map<v3s16, u8> unlighted_nodes;
248         core::map<v3s16, u8>::Iterator j;
249         j = from_nodes.getIterator();
250
251         /*
252                 Initialize block cache
253         */
254         v3s16 blockpos_last;
255         MapBlock *block = NULL;
256         // Cache this a bit, too
257         bool block_checked_in_modified = false;
258         
259         for(; j.atEnd() == false; j++)
260         {
261                 v3s16 pos = j.getNode()->getKey();
262                 v3s16 blockpos = getNodeBlockPos(pos);
263                 
264                 // Only fetch a new block if the block position has changed
265                 try{
266                         if(block == NULL || blockpos != blockpos_last){
267                                 block = getBlockNoCreate(blockpos);
268                                 blockpos_last = blockpos;
269
270                                 block_checked_in_modified = false;
271                                 blockchangecount++;
272                         }
273                 }
274                 catch(InvalidPositionException &e)
275                 {
276                         continue;
277                 }
278
279                 if(block->isDummy())
280                         continue;
281
282                 // Calculate relative position in block
283                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
284
285                 // Get node straight from the block
286                 MapNode n = block->getNode(relpos);
287
288                 u8 oldlight = j.getNode()->getValue();
289
290                 // Loop through 6 neighbors
291                 for(u16 i=0; i<6; i++)
292                 {
293                         // Get the position of the neighbor node
294                         v3s16 n2pos = pos + dirs[i];
295
296                         // Get the block where the node is located
297                         v3s16 blockpos = getNodeBlockPos(n2pos);
298
299                         try
300                         {
301                                 // Only fetch a new block if the block position has changed
302                                 try{
303                                         if(block == NULL || blockpos != blockpos_last){
304                                                 block = getBlockNoCreate(blockpos);
305                                                 blockpos_last = blockpos;
306
307                                                 block_checked_in_modified = false;
308                                                 blockchangecount++;
309                                         }
310                                 }
311                                 catch(InvalidPositionException &e)
312                                 {
313                                         continue;
314                                 }
315
316                                 // Calculate relative position in block
317                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
318                                 // Get node straight from the block
319                                 MapNode n2 = block->getNode(relpos);
320
321                                 bool changed = false;
322
323                                 //TODO: Optimize output by optimizing light_sources?
324
325                                 /*
326                                         If the neighbor is dimmer than what was specified
327                                         as oldlight (the light of the previous node)
328                                 */
329                                 if(n2.getLight(bank) < oldlight)
330                                 {
331                                         /*
332                                                 And the neighbor is transparent and it has some light
333                                         */
334                                         if(n2.light_propagates() && n2.getLight(bank) != 0)
335                                         {
336                                                 /*
337                                                         Set light to 0 and add to queue
338                                                 */
339
340                                                 u8 current_light = n2.getLight(bank);
341                                                 n2.setLight(bank, 0);
342                                                 block->setNode(relpos, n2);
343
344                                                 unlighted_nodes.insert(n2pos, current_light);
345                                                 changed = true;
346
347                                                 /*
348                                                         Remove from light_sources if it is there
349                                                         NOTE: This doesn't happen nearly at all
350                                                 */
351                                                 /*if(light_sources.find(n2pos))
352                                                 {
353                                                         infostream<<"Removed from light_sources"<<std::endl;
354                                                         light_sources.remove(n2pos);
355                                                 }*/
356                                         }
357
358                                         /*// DEBUG
359                                         if(light_sources.find(n2pos) != NULL)
360                                                 light_sources.remove(n2pos);*/
361                                 }
362                                 else{
363                                         light_sources.insert(n2pos, true);
364                                 }
365
366                                 // Add to modified_blocks
367                                 if(changed == true && block_checked_in_modified == false)
368                                 {
369                                         // If the block is not found in modified_blocks, add.
370                                         if(modified_blocks.find(blockpos) == NULL)
371                                         {
372                                                 modified_blocks.insert(blockpos, block);
373                                         }
374                                         block_checked_in_modified = true;
375                                 }
376                         }
377                         catch(InvalidPositionException &e)
378                         {
379                                 continue;
380                         }
381                 }
382         }
383
384         /*infostream<<"unspreadLight(): Changed block "
385                         <<blockchangecount<<" times"
386                         <<" for "<<from_nodes.size()<<" nodes"
387                         <<std::endl;*/
388
389         if(unlighted_nodes.size() > 0)
390                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
391 }
392
393 /*
394         A single-node wrapper of the above
395 */
396 void Map::unLightNeighbors(enum LightBank bank,
397                 v3s16 pos, u8 lightwas,
398                 core::map<v3s16, bool> & light_sources,
399                 core::map<v3s16, MapBlock*>  & modified_blocks)
400 {
401         core::map<v3s16, u8> from_nodes;
402         from_nodes.insert(pos, lightwas);
403
404         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
405 }
406
407 /*
408         Lights neighbors of from_nodes, collects all them and then
409         goes on recursively.
410 */
411 void Map::spreadLight(enum LightBank bank,
412                 core::map<v3s16, bool> & from_nodes,
413                 core::map<v3s16, MapBlock*> & modified_blocks)
414 {
415         const v3s16 dirs[6] = {
416                 v3s16(0,0,1), // back
417                 v3s16(0,1,0), // top
418                 v3s16(1,0,0), // right
419                 v3s16(0,0,-1), // front
420                 v3s16(0,-1,0), // bottom
421                 v3s16(-1,0,0), // left
422         };
423
424         if(from_nodes.size() == 0)
425                 return;
426
427         u32 blockchangecount = 0;
428
429         core::map<v3s16, bool> lighted_nodes;
430         core::map<v3s16, bool>::Iterator j;
431         j = from_nodes.getIterator();
432
433         /*
434                 Initialize block cache
435         */
436         v3s16 blockpos_last;
437         MapBlock *block = NULL;
438         // Cache this a bit, too
439         bool block_checked_in_modified = false;
440
441         for(; j.atEnd() == false; j++)
442         //for(; j != from_nodes.end(); j++)
443         {
444                 v3s16 pos = j.getNode()->getKey();
445                 //v3s16 pos = *j;
446                 //infostream<<"pos=("<<pos.X<<","<<pos.Y<<","<<pos.Z<<")"<<std::endl;
447                 v3s16 blockpos = getNodeBlockPos(pos);
448
449                 // Only fetch a new block if the block position has changed
450                 try{
451                         if(block == NULL || blockpos != blockpos_last){
452                                 block = getBlockNoCreate(blockpos);
453                                 blockpos_last = blockpos;
454
455                                 block_checked_in_modified = false;
456                                 blockchangecount++;
457                         }
458                 }
459                 catch(InvalidPositionException &e)
460                 {
461                         continue;
462                 }
463
464                 if(block->isDummy())
465                         continue;
466
467                 // Calculate relative position in block
468                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
469
470                 // Get node straight from the block
471                 MapNode n = block->getNode(relpos);
472
473                 u8 oldlight = n.getLight(bank);
474                 u8 newlight = diminish_light(oldlight);
475
476                 // Loop through 6 neighbors
477                 for(u16 i=0; i<6; i++){
478                         // Get the position of the neighbor node
479                         v3s16 n2pos = pos + dirs[i];
480
481                         // Get the block where the node is located
482                         v3s16 blockpos = getNodeBlockPos(n2pos);
483
484                         try
485                         {
486                                 // Only fetch a new block if the block position has changed
487                                 try{
488                                         if(block == NULL || blockpos != blockpos_last){
489                                                 block = getBlockNoCreate(blockpos);
490                                                 blockpos_last = blockpos;
491
492                                                 block_checked_in_modified = false;
493                                                 blockchangecount++;
494                                         }
495                                 }
496                                 catch(InvalidPositionException &e)
497                                 {
498                                         continue;
499                                 }
500
501                                 // Calculate relative position in block
502                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
503                                 // Get node straight from the block
504                                 MapNode n2 = block->getNode(relpos);
505
506                                 bool changed = false;
507                                 /*
508                                         If the neighbor is brighter than the current node,
509                                         add to list (it will light up this node on its turn)
510                                 */
511                                 if(n2.getLight(bank) > undiminish_light(oldlight))
512                                 {
513                                         lighted_nodes.insert(n2pos, true);
514                                         //lighted_nodes.push_back(n2pos);
515                                         changed = true;
516                                 }
517                                 /*
518                                         If the neighbor is dimmer than how much light this node
519                                         would spread on it, add to list
520                                 */
521                                 if(n2.getLight(bank) < newlight)
522                                 {
523                                         if(n2.light_propagates())
524                                         {
525                                                 n2.setLight(bank, newlight);
526                                                 block->setNode(relpos, n2);
527                                                 lighted_nodes.insert(n2pos, true);
528                                                 //lighted_nodes.push_back(n2pos);
529                                                 changed = true;
530                                         }
531                                 }
532
533                                 // Add to modified_blocks
534                                 if(changed == true && block_checked_in_modified == false)
535                                 {
536                                         // If the block is not found in modified_blocks, add.
537                                         if(modified_blocks.find(blockpos) == NULL)
538                                         {
539                                                 modified_blocks.insert(blockpos, block);
540                                         }
541                                         block_checked_in_modified = true;
542                                 }
543                         }
544                         catch(InvalidPositionException &e)
545                         {
546                                 continue;
547                         }
548                 }
549         }
550
551         /*infostream<<"spreadLight(): Changed block "
552                         <<blockchangecount<<" times"
553                         <<" for "<<from_nodes.size()<<" nodes"
554                         <<std::endl;*/
555
556         if(lighted_nodes.size() > 0)
557                 spreadLight(bank, lighted_nodes, modified_blocks);
558 }
559
560 /*
561         A single-node source variation of the above.
562 */
563 void Map::lightNeighbors(enum LightBank bank,
564                 v3s16 pos,
565                 core::map<v3s16, MapBlock*> & modified_blocks)
566 {
567         core::map<v3s16, bool> from_nodes;
568         from_nodes.insert(pos, true);
569         spreadLight(bank, from_nodes, modified_blocks);
570 }
571
572 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
573 {
574         v3s16 dirs[6] = {
575                 v3s16(0,0,1), // back
576                 v3s16(0,1,0), // top
577                 v3s16(1,0,0), // right
578                 v3s16(0,0,-1), // front
579                 v3s16(0,-1,0), // bottom
580                 v3s16(-1,0,0), // left
581         };
582
583         u8 brightest_light = 0;
584         v3s16 brightest_pos(0,0,0);
585         bool found_something = false;
586
587         // Loop through 6 neighbors
588         for(u16 i=0; i<6; i++){
589                 // Get the position of the neighbor node
590                 v3s16 n2pos = p + dirs[i];
591                 MapNode n2;
592                 try{
593                         n2 = getNode(n2pos);
594                 }
595                 catch(InvalidPositionException &e)
596                 {
597                         continue;
598                 }
599                 if(n2.getLight(bank) > brightest_light || found_something == false){
600                         brightest_light = n2.getLight(bank);
601                         brightest_pos = n2pos;
602                         found_something = true;
603                 }
604         }
605
606         if(found_something == false)
607                 throw InvalidPositionException();
608
609         return brightest_pos;
610 }
611
612 /*
613         Propagates sunlight down from a node.
614         Starting point gets sunlight.
615
616         Returns the lowest y value of where the sunlight went.
617
618         Mud is turned into grass in where the sunlight stops.
619 */
620 s16 Map::propagateSunlight(v3s16 start,
621                 core::map<v3s16, MapBlock*> & modified_blocks)
622 {
623         s16 y = start.Y;
624         for(; ; y--)
625         {
626                 v3s16 pos(start.X, y, start.Z);
627
628                 v3s16 blockpos = getNodeBlockPos(pos);
629                 MapBlock *block;
630                 try{
631                         block = getBlockNoCreate(blockpos);
632                 }
633                 catch(InvalidPositionException &e)
634                 {
635                         break;
636                 }
637
638                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
639                 MapNode n = block->getNode(relpos);
640
641                 if(n.sunlight_propagates())
642                 {
643                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
644                         block->setNode(relpos, n);
645
646                         modified_blocks.insert(blockpos, block);
647                 }
648                 else
649                 {
650                         /*// Turn mud into grass
651                         if(n.getContent() == CONTENT_MUD)
652                         {
653                                 n.setContent(CONTENT_GRASS);
654                                 block->setNode(relpos, n);
655                                 modified_blocks.insert(blockpos, block);
656                         }*/
657
658                         // Sunlight goes no further
659                         break;
660                 }
661         }
662         return y + 1;
663 }
664
665 void Map::updateLighting(enum LightBank bank,
666                 core::map<v3s16, MapBlock*> & a_blocks,
667                 core::map<v3s16, MapBlock*> & modified_blocks)
668 {
669         /*m_dout<<DTIME<<"Map::updateLighting(): "
670                         <<a_blocks.size()<<" blocks."<<std::endl;*/
671
672         //TimeTaker timer("updateLighting");
673
674         // For debugging
675         //bool debug=true;
676         //u32 count_was = modified_blocks.size();
677
678         core::map<v3s16, MapBlock*> blocks_to_update;
679
680         core::map<v3s16, bool> light_sources;
681
682         core::map<v3s16, u8> unlight_from;
683
684         core::map<v3s16, MapBlock*>::Iterator i;
685         i = a_blocks.getIterator();
686         for(; i.atEnd() == false; i++)
687         {
688                 MapBlock *block = i.getNode()->getValue();
689
690                 for(;;)
691                 {
692                         // Don't bother with dummy blocks.
693                         if(block->isDummy())
694                                 break;
695
696                         v3s16 pos = block->getPos();
697                         modified_blocks.insert(pos, block);
698
699                         blocks_to_update.insert(pos, block);
700
701                         /*
702                                 Clear all light from block
703                         */
704                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
705                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
706                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
707                         {
708
709                                 try{
710                                         v3s16 p(x,y,z);
711                                         MapNode n = block->getNode(v3s16(x,y,z));
712                                         u8 oldlight = n.getLight(bank);
713                                         n.setLight(bank, 0);
714                                         block->setNode(v3s16(x,y,z), n);
715
716                                         // Collect borders for unlighting
717                                         if(x==0 || x == MAP_BLOCKSIZE-1
718                                         || y==0 || y == MAP_BLOCKSIZE-1
719                                         || z==0 || z == MAP_BLOCKSIZE-1)
720                                         {
721                                                 v3s16 p_map = p + v3s16(
722                                                                 MAP_BLOCKSIZE*pos.X,
723                                                                 MAP_BLOCKSIZE*pos.Y,
724                                                                 MAP_BLOCKSIZE*pos.Z);
725                                                 unlight_from.insert(p_map, oldlight);
726                                         }
727                                 }
728                                 catch(InvalidPositionException &e)
729                                 {
730                                         /*
731                                                 This would happen when dealing with a
732                                                 dummy block.
733                                         */
734                                         //assert(0);
735                                         infostream<<"updateLighting(): InvalidPositionException"
736                                                         <<std::endl;
737                                 }
738                         }
739
740                         if(bank == LIGHTBANK_DAY)
741                         {
742                                 bool bottom_valid = block->propagateSunlight(light_sources);
743
744                                 // If bottom is valid, we're done.
745                                 if(bottom_valid)
746                                         break;
747                         }
748                         else if(bank == LIGHTBANK_NIGHT)
749                         {
750                                 // For night lighting, sunlight is not propagated
751                                 break;
752                         }
753                         else
754                         {
755                                 // Invalid lighting bank
756                                 assert(0);
757                         }
758
759                         /*infostream<<"Bottom for sunlight-propagated block ("
760                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
761                                         <<std::endl;*/
762
763                         // Bottom sunlight is not valid; get the block and loop to it
764
765                         pos.Y--;
766                         try{
767                                 block = getBlockNoCreate(pos);
768                         }
769                         catch(InvalidPositionException &e)
770                         {
771                                 assert(0);
772                         }
773
774                 }
775         }
776         
777         /*
778                 Enable this to disable proper lighting for speeding up map
779                 generation for testing or whatever
780         */
781 #if 0
782         //if(g_settings->get(""))
783         {
784                 core::map<v3s16, MapBlock*>::Iterator i;
785                 i = blocks_to_update.getIterator();
786                 for(; i.atEnd() == false; i++)
787                 {
788                         MapBlock *block = i.getNode()->getValue();
789                         v3s16 p = block->getPos();
790                         block->setLightingExpired(false);
791                 }
792                 return;
793         }
794 #endif
795
796 #if 0
797         {
798                 TimeTaker timer("unspreadLight");
799                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
800         }
801
802         if(debug)
803         {
804                 u32 diff = modified_blocks.size() - count_was;
805                 count_was = modified_blocks.size();
806                 infostream<<"unspreadLight modified "<<diff<<std::endl;
807         }
808
809         {
810                 TimeTaker timer("spreadLight");
811                 spreadLight(bank, light_sources, modified_blocks);
812         }
813
814         if(debug)
815         {
816                 u32 diff = modified_blocks.size() - count_was;
817                 count_was = modified_blocks.size();
818                 infostream<<"spreadLight modified "<<diff<<std::endl;
819         }
820 #endif
821
822         {
823                 //MapVoxelManipulator vmanip(this);
824
825                 // Make a manual voxel manipulator and load all the blocks
826                 // that touch the requested blocks
827                 ManualMapVoxelManipulator vmanip(this);
828                 core::map<v3s16, MapBlock*>::Iterator i;
829                 i = blocks_to_update.getIterator();
830                 for(; i.atEnd() == false; i++)
831                 {
832                         MapBlock *block = i.getNode()->getValue();
833                         v3s16 p = block->getPos();
834
835                         // Add all surrounding blocks
836                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
837
838                         /*
839                                 Add all surrounding blocks that have up-to-date lighting
840                                 NOTE: This doesn't quite do the job (not everything
841                                           appropriate is lighted)
842                         */
843                         /*for(s16 z=-1; z<=1; z++)
844                         for(s16 y=-1; y<=1; y++)
845                         for(s16 x=-1; x<=1; x++)
846                         {
847                                 v3s16 p(x,y,z);
848                                 MapBlock *block = getBlockNoCreateNoEx(p);
849                                 if(block == NULL)
850                                         continue;
851                                 if(block->isDummy())
852                                         continue;
853                                 if(block->getLightingExpired())
854                                         continue;
855                                 vmanip.initialEmerge(p, p);
856                         }*/
857
858                         // Lighting of block will be updated completely
859                         block->setLightingExpired(false);
860                 }
861
862                 {
863                         //TimeTaker timer("unSpreadLight");
864                         vmanip.unspreadLight(bank, unlight_from, light_sources);
865                 }
866                 {
867                         //TimeTaker timer("spreadLight");
868                         vmanip.spreadLight(bank, light_sources);
869                 }
870                 {
871                         //TimeTaker timer("blitBack");
872                         vmanip.blitBack(modified_blocks);
873                 }
874                 /*infostream<<"emerge_time="<<emerge_time<<std::endl;
875                 emerge_time = 0;*/
876         }
877
878         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
879 }
880
881 void Map::updateLighting(core::map<v3s16, MapBlock*> & a_blocks,
882                 core::map<v3s16, MapBlock*> & modified_blocks)
883 {
884         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
885         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
886
887         /*
888                 Update information about whether day and night light differ
889         */
890         for(core::map<v3s16, MapBlock*>::Iterator
891                         i = modified_blocks.getIterator();
892                         i.atEnd() == false; i++)
893         {
894                 MapBlock *block = i.getNode()->getValue();
895                 block->updateDayNightDiff();
896         }
897 }
898
899 /*
900 */
901 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
902                 core::map<v3s16, MapBlock*> &modified_blocks, std::string &player_name)
903 {
904         /*PrintInfo(m_dout);
905         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
906                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
907
908         /*
909                 From this node to nodes underneath:
910                 If lighting is sunlight (1.0), unlight neighbours and
911                 set lighting to 0.
912                 Else discontinue.
913         */
914
915         v3s16 toppos = p + v3s16(0,1,0);
916         v3s16 bottompos = p + v3s16(0,-1,0);
917
918         bool node_under_sunlight = true;
919         core::map<v3s16, bool> light_sources;
920
921         /*
922                 If there is a node at top and it doesn't have sunlight,
923                 there has not been any sunlight going down.
924
925                 Otherwise there probably is.
926         */
927         try{
928                 MapNode topnode = getNode(toppos);
929
930                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
931                         node_under_sunlight = false;
932         }
933         catch(InvalidPositionException &e)
934         {
935         }
936
937 #if 0
938         /*
939                 If the new node is solid and there is grass below, change it to mud
940         */
941         if(content_features(n).walkable == true)
942         {
943                 try{
944                         MapNode bottomnode = getNode(bottompos);
945
946                         if(bottomnode.getContent() == CONTENT_GRASS
947                                         || bottomnode.getContent() == CONTENT_GRASS_FOOTSTEPS)
948                         {
949                                 bottomnode.setContent(CONTENT_MUD);
950                                 setNode(bottompos, bottomnode);
951                         }
952                 }
953                 catch(InvalidPositionException &e)
954                 {
955                 }
956         }
957 #endif
958
959 #if 0
960         /*
961                 If the new node is mud and it is under sunlight, change it
962                 to grass
963         */
964         if(n.getContent() == CONTENT_MUD && node_under_sunlight)
965         {
966                 n.setContent(CONTENT_GRASS);
967         }
968 #endif
969
970         /*
971                 Remove all light that has come out of this node
972         */
973
974         enum LightBank banks[] =
975         {
976                 LIGHTBANK_DAY,
977                 LIGHTBANK_NIGHT
978         };
979         for(s32 i=0; i<2; i++)
980         {
981                 enum LightBank bank = banks[i];
982
983                 u8 lightwas = getNode(p).getLight(bank);
984
985                 // Add the block of the added node to modified_blocks
986                 v3s16 blockpos = getNodeBlockPos(p);
987                 MapBlock * block = getBlockNoCreate(blockpos);
988                 assert(block != NULL);
989                 modified_blocks.insert(blockpos, block);
990
991                 assert(isValidPosition(p));
992
993                 // Unlight neighbours of node.
994                 // This means setting light of all consequent dimmer nodes
995                 // to 0.
996                 // This also collects the nodes at the border which will spread
997                 // light again into this.
998                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
999
1000                 n.setLight(bank, 0);
1001         }
1002
1003         /*
1004                 If node lets sunlight through and is under sunlight, it has
1005                 sunlight too.
1006         */
1007         if(node_under_sunlight && content_features(n).sunlight_propagates)
1008         {
1009                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
1010         }
1011
1012         /*
1013                 Set the node on the map
1014         */
1015
1016         setNode(p, n);
1017
1018         /*
1019                 Add intial metadata
1020         */
1021
1022         NodeMetadata *meta_proto = content_features(n).initial_metadata;
1023         if(meta_proto)
1024         {
1025                 NodeMetadata *meta = meta_proto->clone();
1026                 meta->setOwner(player_name);
1027                 setNodeMetadata(p, meta);
1028         }
1029
1030         /*
1031                 If node is under sunlight and doesn't let sunlight through,
1032                 take all sunlighted nodes under it and clear light from them
1033                 and from where the light has been spread.
1034                 TODO: This could be optimized by mass-unlighting instead
1035                           of looping
1036         */
1037         if(node_under_sunlight && !content_features(n).sunlight_propagates)
1038         {
1039                 s16 y = p.Y - 1;
1040                 for(;; y--){
1041                         //m_dout<<DTIME<<"y="<<y<<std::endl;
1042                         v3s16 n2pos(p.X, y, p.Z);
1043
1044                         MapNode n2;
1045                         try{
1046                                 n2 = getNode(n2pos);
1047                         }
1048                         catch(InvalidPositionException &e)
1049                         {
1050                                 break;
1051                         }
1052
1053                         if(n2.getLight(LIGHTBANK_DAY) == LIGHT_SUN)
1054                         {
1055                                 unLightNeighbors(LIGHTBANK_DAY,
1056                                                 n2pos, n2.getLight(LIGHTBANK_DAY),
1057                                                 light_sources, modified_blocks);
1058                                 n2.setLight(LIGHTBANK_DAY, 0);
1059                                 setNode(n2pos, n2);
1060                         }
1061                         else
1062                                 break;
1063                 }
1064         }
1065
1066         for(s32 i=0; i<2; i++)
1067         {
1068                 enum LightBank bank = banks[i];
1069
1070                 /*
1071                         Spread light from all nodes that might be capable of doing so
1072                 */
1073                 spreadLight(bank, light_sources, modified_blocks);
1074         }
1075
1076         /*
1077                 Update information about whether day and night light differ
1078         */
1079         for(core::map<v3s16, MapBlock*>::Iterator
1080                         i = modified_blocks.getIterator();
1081                         i.atEnd() == false; i++)
1082         {
1083                 MapBlock *block = i.getNode()->getValue();
1084                 block->updateDayNightDiff();
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                 try
1103                 {
1104
1105                 v3s16 p2 = p + dirs[i];
1106
1107                 MapNode n2 = getNode(p2);
1108                 if(content_liquid(n2.getContent()) || n2.getContent() == CONTENT_AIR)
1109                 {
1110                         m_transforming_liquid.push_back(p2);
1111                 }
1112
1113                 }catch(InvalidPositionException &e)
1114                 {
1115                 }
1116         }
1117 }
1118
1119 /*
1120 */
1121 void Map::removeNodeAndUpdate(v3s16 p,
1122                 core::map<v3s16, MapBlock*> &modified_blocks)
1123 {
1124         /*PrintInfo(m_dout);
1125         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1126                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1127
1128         bool node_under_sunlight = true;
1129
1130         v3s16 toppos = p + v3s16(0,1,0);
1131
1132         // Node will be replaced with this
1133         content_t replace_material = CONTENT_AIR;
1134
1135         /*
1136                 If there is a node at top and it doesn't have sunlight,
1137                 there will be no sunlight going down.
1138         */
1139         try{
1140                 MapNode topnode = getNode(toppos);
1141
1142                 if(topnode.getLight(LIGHTBANK_DAY) != LIGHT_SUN)
1143                         node_under_sunlight = false;
1144         }
1145         catch(InvalidPositionException &e)
1146         {
1147         }
1148
1149         core::map<v3s16, bool> light_sources;
1150
1151         enum LightBank banks[] =
1152         {
1153                 LIGHTBANK_DAY,
1154                 LIGHTBANK_NIGHT
1155         };
1156         for(s32 i=0; i<2; i++)
1157         {
1158                 enum LightBank bank = banks[i];
1159
1160                 /*
1161                         Unlight neighbors (in case the node is a light source)
1162                 */
1163                 unLightNeighbors(bank, p,
1164                                 getNode(p).getLight(bank),
1165                                 light_sources, modified_blocks);
1166         }
1167
1168         /*
1169                 Remove node metadata
1170         */
1171
1172         removeNodeMetadata(p);
1173
1174         /*
1175                 Remove the node.
1176                 This also clears the lighting.
1177         */
1178
1179         MapNode n;
1180         n.setContent(replace_material);
1181         setNode(p, n);
1182
1183         for(s32 i=0; i<2; i++)
1184         {
1185                 enum LightBank bank = banks[i];
1186
1187                 /*
1188                         Recalculate lighting
1189                 */
1190                 spreadLight(bank, light_sources, modified_blocks);
1191         }
1192
1193         // Add the block of the removed node to modified_blocks
1194         v3s16 blockpos = getNodeBlockPos(p);
1195         MapBlock * block = getBlockNoCreate(blockpos);
1196         assert(block != NULL);
1197         modified_blocks.insert(blockpos, block);
1198
1199         /*
1200                 If the removed node was under sunlight, propagate the
1201                 sunlight down from it and then light all neighbors
1202                 of the propagated blocks.
1203         */
1204         if(node_under_sunlight)
1205         {
1206                 s16 ybottom = propagateSunlight(p, modified_blocks);
1207                 /*m_dout<<DTIME<<"Node was under sunlight. "
1208                                 "Propagating sunlight";
1209                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1210                 s16 y = p.Y;
1211                 for(; y >= ybottom; y--)
1212                 {
1213                         v3s16 p2(p.X, y, p.Z);
1214                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1215                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1216                                         <<std::endl;*/
1217                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1218                 }
1219         }
1220         else
1221         {
1222                 // Set the lighting of this node to 0
1223                 // TODO: Is this needed? Lighting is cleared up there already.
1224                 try{
1225                         MapNode n = getNode(p);
1226                         n.setLight(LIGHTBANK_DAY, 0);
1227                         setNode(p, n);
1228                 }
1229                 catch(InvalidPositionException &e)
1230                 {
1231                         assert(0);
1232                 }
1233         }
1234
1235         for(s32 i=0; i<2; i++)
1236         {
1237                 enum LightBank bank = banks[i];
1238
1239                 // Get the brightest neighbour node and propagate light from it
1240                 v3s16 n2p = getBrightestNeighbour(bank, p);
1241                 try{
1242                         MapNode n2 = getNode(n2p);
1243                         lightNeighbors(bank, n2p, modified_blocks);
1244                 }
1245                 catch(InvalidPositionException &e)
1246                 {
1247                 }
1248         }
1249
1250         /*
1251                 Update information about whether day and night light differ
1252         */
1253         for(core::map<v3s16, MapBlock*>::Iterator
1254                         i = modified_blocks.getIterator();
1255                         i.atEnd() == false; i++)
1256         {
1257                 MapBlock *block = i.getNode()->getValue();
1258                 block->updateDayNightDiff();
1259         }
1260
1261         /*
1262                 Add neighboring liquid nodes and this node to transform queue.
1263                 (it's vital for the node itself to get updated last.)
1264         */
1265         v3s16 dirs[7] = {
1266                 v3s16(0,0,1), // back
1267                 v3s16(0,1,0), // top
1268                 v3s16(1,0,0), // right
1269                 v3s16(0,0,-1), // front
1270                 v3s16(0,-1,0), // bottom
1271                 v3s16(-1,0,0), // left
1272                 v3s16(0,0,0), // self
1273         };
1274         for(u16 i=0; i<7; i++)
1275         {
1276                 try
1277                 {
1278
1279                 v3s16 p2 = p + dirs[i];
1280
1281                 MapNode n2 = getNode(p2);
1282                 if(content_liquid(n2.getContent()) || n2.getContent() == CONTENT_AIR)
1283                 {
1284                         m_transforming_liquid.push_back(p2);
1285                 }
1286
1287                 }catch(InvalidPositionException &e)
1288                 {
1289                 }
1290         }
1291 }
1292
1293 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1294 {
1295         MapEditEvent event;
1296         event.type = MEET_ADDNODE;
1297         event.p = p;
1298         event.n = n;
1299
1300         bool succeeded = true;
1301         try{
1302                 core::map<v3s16, MapBlock*> modified_blocks;
1303                 std::string st = std::string("");
1304                 addNodeAndUpdate(p, n, modified_blocks, st);
1305
1306                 // Copy modified_blocks to event
1307                 for(core::map<v3s16, MapBlock*>::Iterator
1308                                 i = modified_blocks.getIterator();
1309                                 i.atEnd()==false; i++)
1310                 {
1311                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1312                 }
1313         }
1314         catch(InvalidPositionException &e){
1315                 succeeded = false;
1316         }
1317
1318         dispatchEvent(&event);
1319
1320         return succeeded;
1321 }
1322
1323 bool Map::removeNodeWithEvent(v3s16 p)
1324 {
1325         MapEditEvent event;
1326         event.type = MEET_REMOVENODE;
1327         event.p = p;
1328
1329         bool succeeded = true;
1330         try{
1331                 core::map<v3s16, MapBlock*> modified_blocks;
1332                 removeNodeAndUpdate(p, modified_blocks);
1333
1334                 // Copy modified_blocks to event
1335                 for(core::map<v3s16, MapBlock*>::Iterator
1336                                 i = modified_blocks.getIterator();
1337                                 i.atEnd()==false; i++)
1338                 {
1339                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1340                 }
1341         }
1342         catch(InvalidPositionException &e){
1343                 succeeded = false;
1344         }
1345
1346         dispatchEvent(&event);
1347
1348         return succeeded;
1349 }
1350
1351 bool Map::dayNightDiffed(v3s16 blockpos)
1352 {
1353         try{
1354                 v3s16 p = blockpos + v3s16(0,0,0);
1355                 MapBlock *b = getBlockNoCreate(p);
1356                 if(b->dayNightDiffed())
1357                         return true;
1358         }
1359         catch(InvalidPositionException &e){}
1360         // Leading edges
1361         try{
1362                 v3s16 p = blockpos + v3s16(-1,0,0);
1363                 MapBlock *b = getBlockNoCreate(p);
1364                 if(b->dayNightDiffed())
1365                         return true;
1366         }
1367         catch(InvalidPositionException &e){}
1368         try{
1369                 v3s16 p = blockpos + v3s16(0,-1,0);
1370                 MapBlock *b = getBlockNoCreate(p);
1371                 if(b->dayNightDiffed())
1372                         return true;
1373         }
1374         catch(InvalidPositionException &e){}
1375         try{
1376                 v3s16 p = blockpos + v3s16(0,0,-1);
1377                 MapBlock *b = getBlockNoCreate(p);
1378                 if(b->dayNightDiffed())
1379                         return true;
1380         }
1381         catch(InvalidPositionException &e){}
1382         // Trailing edges
1383         try{
1384                 v3s16 p = blockpos + v3s16(1,0,0);
1385                 MapBlock *b = getBlockNoCreate(p);
1386                 if(b->dayNightDiffed())
1387                         return true;
1388         }
1389         catch(InvalidPositionException &e){}
1390         try{
1391                 v3s16 p = blockpos + v3s16(0,1,0);
1392                 MapBlock *b = getBlockNoCreate(p);
1393                 if(b->dayNightDiffed())
1394                         return true;
1395         }
1396         catch(InvalidPositionException &e){}
1397         try{
1398                 v3s16 p = blockpos + v3s16(0,0,1);
1399                 MapBlock *b = getBlockNoCreate(p);
1400                 if(b->dayNightDiffed())
1401                         return true;
1402         }
1403         catch(InvalidPositionException &e){}
1404
1405         return false;
1406 }
1407
1408 /*
1409         Updates usage timers
1410 */
1411 void Map::timerUpdate(float dtime, float unload_timeout,
1412                 core::list<v3s16> *unloaded_blocks)
1413 {
1414         bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
1415         
1416         core::list<v2s16> sector_deletion_queue;
1417         u32 deleted_blocks_count = 0;
1418         u32 saved_blocks_count = 0;
1419
1420         core::map<v2s16, MapSector*>::Iterator si;
1421
1422         beginSave();
1423         si = m_sectors.getIterator();
1424         for(; si.atEnd() == false; si++)
1425         {
1426                 MapSector *sector = si.getNode()->getValue();
1427
1428                 bool all_blocks_deleted = true;
1429
1430                 core::list<MapBlock*> blocks;
1431                 sector->getBlocks(blocks);
1432                 
1433                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1434                                 i != blocks.end(); i++)
1435                 {
1436                         MapBlock *block = (*i);
1437                         
1438                         block->incrementUsageTimer(dtime);
1439                         
1440                         if(block->getUsageTimer() > unload_timeout)
1441                         {
1442                                 v3s16 p = block->getPos();
1443
1444                                 // Save if modified
1445                                 if(block->getModified() != MOD_STATE_CLEAN
1446                                                 && save_before_unloading)
1447                                 {
1448                                         saveBlock(block);
1449                                         saved_blocks_count++;
1450                                 }
1451
1452                                 // Delete from memory
1453                                 sector->deleteBlock(block);
1454
1455                                 if(unloaded_blocks)
1456                                         unloaded_blocks->push_back(p);
1457
1458                                 deleted_blocks_count++;
1459                         }
1460                         else
1461                         {
1462                                 all_blocks_deleted = false;
1463                         }
1464                 }
1465
1466                 if(all_blocks_deleted)
1467                 {
1468                         sector_deletion_queue.push_back(si.getNode()->getKey());
1469                 }
1470         }
1471         endSave();
1472         
1473         // Finally delete the empty sectors
1474         deleteSectors(sector_deletion_queue);
1475         
1476         if(deleted_blocks_count != 0)
1477         {
1478                 PrintInfo(infostream); // ServerMap/ClientMap:
1479                 infostream<<"Unloaded "<<deleted_blocks_count
1480                                 <<" blocks from memory";
1481                 if(save_before_unloading)
1482                         infostream<<", of which "<<saved_blocks_count<<" were written";
1483                 infostream<<"."<<std::endl;
1484         }
1485 }
1486
1487 void Map::deleteSectors(core::list<v2s16> &list)
1488 {
1489         core::list<v2s16>::Iterator j;
1490         for(j=list.begin(); j!=list.end(); j++)
1491         {
1492                 MapSector *sector = m_sectors[*j];
1493                 // If sector is in sector cache, remove it from there
1494                 if(m_sector_cache == sector)
1495                         m_sector_cache = NULL;
1496                 // Remove from map and delete
1497                 m_sectors.remove(*j);
1498                 delete sector;
1499         }
1500 }
1501
1502 #if 0
1503 void Map::unloadUnusedData(float timeout,
1504                 core::list<v3s16> *deleted_blocks)
1505 {
1506         core::list<v2s16> sector_deletion_queue;
1507         u32 deleted_blocks_count = 0;
1508         u32 saved_blocks_count = 0;
1509
1510         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1511         for(; si.atEnd() == false; si++)
1512         {
1513                 MapSector *sector = si.getNode()->getValue();
1514
1515                 bool all_blocks_deleted = true;
1516
1517                 core::list<MapBlock*> blocks;
1518                 sector->getBlocks(blocks);
1519                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1520                                 i != blocks.end(); i++)
1521                 {
1522                         MapBlock *block = (*i);
1523                         
1524                         if(block->getUsageTimer() > timeout)
1525                         {
1526                                 // Save if modified
1527                                 if(block->getModified() != MOD_STATE_CLEAN)
1528                                 {
1529                                         saveBlock(block);
1530                                         saved_blocks_count++;
1531                                 }
1532                                 // Delete from memory
1533                                 sector->deleteBlock(block);
1534                                 deleted_blocks_count++;
1535                         }
1536                         else
1537                         {
1538                                 all_blocks_deleted = false;
1539                         }
1540                 }
1541
1542                 if(all_blocks_deleted)
1543                 {
1544                         sector_deletion_queue.push_back(si.getNode()->getKey());
1545                 }
1546         }
1547
1548         deleteSectors(sector_deletion_queue);
1549
1550         infostream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
1551                         <<", of which "<<saved_blocks_count<<" were wr."
1552                         <<std::endl;
1553
1554         //return sector_deletion_queue.getSize();
1555         //return deleted_blocks_count;
1556 }
1557 #endif
1558
1559 void Map::PrintInfo(std::ostream &out)
1560 {
1561         out<<"Map: ";
1562 }
1563
1564 #define WATER_DROP_BOOST 4
1565
1566 enum NeighborType {
1567         NEIGHBOR_UPPER,
1568         NEIGHBOR_SAME_LEVEL,
1569         NEIGHBOR_LOWER
1570 };
1571 struct NodeNeighbor {
1572         MapNode n;
1573         NeighborType t;
1574         v3s16 p;
1575 };
1576
1577 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1578 {
1579         DSTACK(__FUNCTION_NAME);
1580         //TimeTaker timer("transformLiquids()");
1581
1582         u32 loopcount = 0;
1583         u32 initial_size = m_transforming_liquid.size();
1584
1585         /*if(initial_size != 0)
1586                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1587
1588         // list of nodes that due to viscosity have not reached their max level height
1589         UniqueQueue<v3s16> must_reflow;
1590         
1591         // List of MapBlocks that will require a lighting update (due to lava)
1592         core::map<v3s16, MapBlock*> lighting_modified_blocks;
1593
1594         while(m_transforming_liquid.size() != 0)
1595         {
1596                 // This should be done here so that it is done when continue is used
1597                 if(loopcount >= initial_size * 3)
1598                         break;
1599                 loopcount++;
1600
1601                 /*
1602                         Get a queued transforming liquid node
1603                 */
1604                 v3s16 p0 = m_transforming_liquid.pop_front();
1605
1606                 MapNode n0 = getNodeNoEx(p0);
1607
1608                 /*
1609                         Collect information about current node
1610                  */
1611                 s8 liquid_level = -1;
1612                 u8 liquid_kind = CONTENT_IGNORE;
1613                 LiquidType liquid_type = content_features(n0.getContent()).liquid_type;
1614                 switch (liquid_type) {
1615                         case LIQUID_SOURCE:
1616                                 liquid_level = LIQUID_LEVEL_SOURCE;
1617                                 liquid_kind = content_features(n0.getContent()).liquid_alternative_flowing;
1618                                 break;
1619                         case LIQUID_FLOWING:
1620                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1621                                 liquid_kind = n0.getContent();
1622                                 break;
1623                         case LIQUID_NONE:
1624                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1625                                 // continue with the next node.
1626                                 if (n0.getContent() != CONTENT_AIR)
1627                                         continue;
1628                                 liquid_kind = CONTENT_AIR;
1629                                 break;
1630                 }
1631
1632                 /*
1633                         Collect information about the environment
1634                  */
1635                 const v3s16 *dirs = g_6dirs;
1636                 NodeNeighbor sources[6]; // surrounding sources
1637                 int num_sources = 0;
1638                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1639                 int num_flows = 0;
1640                 NodeNeighbor airs[6]; // surrounding air
1641                 int num_airs = 0;
1642                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1643                 int num_neutrals = 0;
1644                 bool flowing_down = false;
1645                 for (u16 i = 0; i < 6; i++) {
1646                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1647                         switch (i) {
1648                                 case 1:
1649                                         nt = NEIGHBOR_UPPER;
1650                                         break;
1651                                 case 4:
1652                                         nt = NEIGHBOR_LOWER;
1653                                         break;
1654                         }
1655                         v3s16 npos = p0 + dirs[i];
1656                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
1657                         switch (content_features(nb.n.getContent()).liquid_type) {
1658                                 case LIQUID_NONE:
1659                                         if (nb.n.getContent() == CONTENT_AIR) {
1660                                                 airs[num_airs++] = nb;
1661                                                 // if the current node is a water source the neighbor
1662                                                 // should be enqueded for transformation regardless of whether the
1663                                                 // current node changes or not.
1664                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1665                                                         m_transforming_liquid.push_back(npos);
1666                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1667                                                 if (nb.t == NEIGHBOR_LOWER) {
1668                                                         flowing_down = true;
1669                                                 }
1670                                         } else {
1671                                                 neutrals[num_neutrals++] = nb;
1672                                         }
1673                                         break;
1674                                 case LIQUID_SOURCE:
1675                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter 
1676                                         if (liquid_kind == CONTENT_AIR)
1677                                                 liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing;
1678                                         if (content_features(nb.n.getContent()).liquid_alternative_flowing !=liquid_kind) {
1679                                                 neutrals[num_neutrals++] = nb;
1680                                         } else {
1681                                                 sources[num_sources++] = nb;
1682                                         }
1683                                         break;
1684                                 case LIQUID_FLOWING:
1685                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1686                                         if (liquid_kind == CONTENT_AIR)
1687                                                 liquid_kind = content_features(nb.n.getContent()).liquid_alternative_flowing;
1688                                         if (content_features(nb.n.getContent()).liquid_alternative_flowing != liquid_kind) {
1689                                                 neutrals[num_neutrals++] = nb;
1690                                         } else {
1691                                                 flows[num_flows++] = nb;
1692                                                 if (nb.t == NEIGHBOR_LOWER)
1693                                                         flowing_down = true;
1694                                         }
1695                                         break;
1696                         }
1697                 }
1698
1699                 /*
1700                         decide on the type (and possibly level) of the current node
1701                  */
1702                 content_t new_node_content;
1703                 s8 new_node_level = -1;
1704                 s8 max_node_level = -1;
1705                 if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
1706                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1707                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1708                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1709                         new_node_content = content_features(liquid_kind).liquid_alternative_source;
1710                 } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
1711                         // liquid_kind is set properly, see above
1712                         new_node_content = liquid_kind;
1713                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1714                 } else {
1715                         // no surrounding sources, so get the maximum level that can flow into this node
1716                         for (u16 i = 0; i < num_flows; i++) {
1717                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1718                                 switch (flows[i].t) {
1719                                         case NEIGHBOR_UPPER:
1720                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1721                                                         max_node_level = LIQUID_LEVEL_MAX;
1722                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1723                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1724                                                 } else if (nb_liquid_level > max_node_level)
1725                                                         max_node_level = nb_liquid_level;
1726                                                 break;
1727                                         case NEIGHBOR_LOWER:
1728                                                 break;
1729                                         case NEIGHBOR_SAME_LEVEL:
1730                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1731                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1732                                                         max_node_level = nb_liquid_level - 1;
1733                                                 }
1734                                                 break;
1735                                 }
1736                         }
1737
1738                         u8 viscosity = content_features(liquid_kind).liquid_viscosity;
1739                         if (viscosity > 1 && max_node_level != liquid_level) {
1740                                 // amount to gain, limited by viscosity
1741                                 // must be at least 1 in absolute value
1742                                 s8 level_inc = max_node_level - liquid_level;
1743                                 if (level_inc < -viscosity || level_inc > viscosity)
1744                                         new_node_level = liquid_level + level_inc/viscosity;
1745                                 else if (level_inc < 0)
1746                                         new_node_level = liquid_level - 1;
1747                                 else if (level_inc > 0)
1748                                         new_node_level = liquid_level + 1;
1749                                 if (new_node_level != max_node_level)
1750                                         must_reflow.push_back(p0);
1751                         } else
1752                                 new_node_level = max_node_level;
1753
1754                         if (new_node_level >= 0)
1755                                 new_node_content = liquid_kind;
1756                         else
1757                                 new_node_content = CONTENT_AIR;
1758
1759                 }
1760
1761                 /*
1762                         check if anything has changed. if not, just continue with the next node.
1763                  */
1764                 if (new_node_content == n0.getContent() && (content_features(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1765                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1766                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1767                                                                                  == flowing_down)))
1768                         continue;
1769
1770
1771                 /*
1772                         update the current node
1773                  */
1774                 bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1775                 if (content_features(new_node_content).liquid_type == LIQUID_FLOWING) {
1776                         // set level to last 3 bits, flowing down bit to 4th bit
1777                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1778                 } else {
1779                         // set the liquid level and flow bit to 0
1780                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1781                 }
1782                 n0.setContent(new_node_content);
1783                 setNode(p0, n0);
1784                 v3s16 blockpos = getNodeBlockPos(p0);
1785                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1786                 if(block != NULL) {
1787                         modified_blocks.insert(blockpos, block);
1788                         // If node emits light, MapBlock requires lighting update
1789                         if(content_features(n0).light_source != 0)
1790                                 lighting_modified_blocks[block->getPos()] = block;
1791                 }
1792
1793                 /*
1794                         enqueue neighbors for update if neccessary
1795                  */
1796                 switch (content_features(n0.getContent()).liquid_type) {
1797                         case LIQUID_SOURCE:
1798                         case LIQUID_FLOWING:
1799                                 // make sure source flows into all neighboring nodes
1800                                 for (u16 i = 0; i < num_flows; i++)
1801                                         if (flows[i].t != NEIGHBOR_UPPER)
1802                                                 m_transforming_liquid.push_back(flows[i].p);
1803                                 for (u16 i = 0; i < num_airs; i++)
1804                                         if (airs[i].t != NEIGHBOR_UPPER)
1805                                                 m_transforming_liquid.push_back(airs[i].p);
1806                                 break;
1807                         case LIQUID_NONE:
1808                                 // this flow has turned to air; neighboring flows might need to do the same
1809                                 for (u16 i = 0; i < num_flows; i++)
1810                                         m_transforming_liquid.push_back(flows[i].p);
1811                                 break;
1812                 }
1813         }
1814         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1815         while (must_reflow.size() > 0)
1816                 m_transforming_liquid.push_back(must_reflow.pop_front());
1817         updateLighting(lighting_modified_blocks, modified_blocks);
1818 }
1819
1820 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1821 {
1822         v3s16 blockpos = getNodeBlockPos(p);
1823         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1824         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1825         if(!block){
1826                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1827                                 <<PP(blockpos)<<std::endl;
1828                 block = emergeBlock(blockpos, false);
1829         }
1830         if(!block)
1831         {
1832                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
1833                                 <<std::endl;
1834                 return NULL;
1835         }
1836         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1837         return meta;
1838 }
1839
1840 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1841 {
1842         v3s16 blockpos = getNodeBlockPos(p);
1843         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1844         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1845         if(!block){
1846                 infostream<<"Map::setNodeMetadata(): Need to emerge "
1847                                 <<PP(blockpos)<<std::endl;
1848                 block = emergeBlock(blockpos, false);
1849         }
1850         if(!block)
1851         {
1852                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
1853                                 <<std::endl;
1854                 return;
1855         }
1856         block->m_node_metadata.set(p_rel, meta);
1857 }
1858
1859 void Map::removeNodeMetadata(v3s16 p)
1860 {
1861         v3s16 blockpos = getNodeBlockPos(p);
1862         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1863         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1864         if(block == NULL)
1865         {
1866                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1867                                 <<std::endl;
1868                 return;
1869         }
1870         block->m_node_metadata.remove(p_rel);
1871 }
1872
1873 void Map::nodeMetadataStep(float dtime,
1874                 core::map<v3s16, MapBlock*> &changed_blocks)
1875 {
1876         /*
1877                 NOTE:
1878                 Currently there is no way to ensure that all the necessary
1879                 blocks are loaded when this is run. (They might get unloaded)
1880                 NOTE: ^- Actually, that might not be so. In a quick test it
1881                 reloaded a block with a furnace when I walked back to it from
1882                 a distance.
1883         */
1884         core::map<v2s16, MapSector*>::Iterator si;
1885         si = m_sectors.getIterator();
1886         for(; si.atEnd() == false; si++)
1887         {
1888                 MapSector *sector = si.getNode()->getValue();
1889                 core::list< MapBlock * > sectorblocks;
1890                 sector->getBlocks(sectorblocks);
1891                 core::list< MapBlock * >::Iterator i;
1892                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1893                 {
1894                         MapBlock *block = *i;
1895                         bool changed = block->m_node_metadata.step(dtime);
1896                         if(changed)
1897                                 changed_blocks[block->getPos()] = block;
1898                 }
1899         }
1900 }
1901
1902 /*
1903         ServerMap
1904 */
1905
1906 ServerMap::ServerMap(std::string savedir):
1907         Map(dout_server),
1908         m_seed(0),
1909         m_map_metadata_changed(true),
1910         m_database(NULL),
1911         m_database_read(NULL),
1912         m_database_write(NULL)
1913 {
1914         infostream<<__FUNCTION_NAME<<std::endl;
1915
1916         //m_chunksize = 8; // Takes a few seconds
1917
1918         if (g_settings->get("fixed_map_seed").empty())
1919         {
1920                 m_seed = (((u64)(myrand()%0xffff)<<0)
1921                                 + ((u64)(myrand()%0xffff)<<16)
1922                                 + ((u64)(myrand()%0xffff)<<32)
1923                                 + ((u64)(myrand()%0xffff)<<48));
1924         }
1925         else
1926         {
1927                 m_seed = g_settings->getU64("fixed_map_seed");
1928         }
1929
1930         /*
1931                 Experimental and debug stuff
1932         */
1933
1934         {
1935         }
1936
1937         /*
1938                 Try to load map; if not found, create a new one.
1939         */
1940
1941         m_savedir = savedir;
1942         m_map_saving_enabled = false;
1943
1944         try
1945         {
1946                 // If directory exists, check contents and load if possible
1947                 if(fs::PathExists(m_savedir))
1948                 {
1949                         // If directory is empty, it is safe to save into it.
1950                         if(fs::GetDirListing(m_savedir).size() == 0)
1951                         {
1952                                 infostream<<"Server: Empty save directory is valid."
1953                                                 <<std::endl;
1954                                 m_map_saving_enabled = true;
1955                         }
1956                         else
1957                         {
1958                                 try{
1959                                         // Load map metadata (seed, chunksize)
1960                                         loadMapMeta();
1961                                 }
1962                                 catch(FileNotGoodException &e){
1963                                         infostream<<"WARNING: Could not load map metadata"
1964                                                         //<<" Disabling chunk-based generator."
1965                                                         <<std::endl;
1966                                         //m_chunksize = 0;
1967                                 }
1968
1969                                 /*try{
1970                                         // Load chunk metadata
1971                                         loadChunkMeta();
1972                                 }
1973                                 catch(FileNotGoodException &e){
1974                                         infostream<<"WARNING: Could not load chunk metadata."
1975                                                         <<" Disabling chunk-based generator."
1976                                                         <<std::endl;
1977                                         m_chunksize = 0;
1978                                 }*/
1979
1980                                 /*infostream<<"Server: Successfully loaded chunk "
1981                                                 "metadata and sector (0,0) from "<<savedir<<
1982                                                 ", assuming valid save directory."
1983                                                 <<std::endl;*/
1984
1985                                 infostream<<"Server: Successfully loaded map "
1986                                                 <<"and chunk metadata from "<<savedir
1987                                                 <<", assuming valid save directory."
1988                                                 <<std::endl;
1989
1990                                 m_map_saving_enabled = true;
1991                                 // Map loaded, not creating new one
1992                                 return;
1993                         }
1994                 }
1995                 // If directory doesn't exist, it is safe to save to it
1996                 else{
1997                         m_map_saving_enabled = true;
1998                 }
1999         }
2000         catch(std::exception &e)
2001         {
2002                 infostream<<"WARNING: Server: Failed to load map from "<<savedir
2003                                 <<", exception: "<<e.what()<<std::endl;
2004                 infostream<<"Please remove the map or fix it."<<std::endl;
2005                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2006         }
2007
2008         infostream<<"Initializing new map."<<std::endl;
2009
2010         // Create zero sector
2011         emergeSector(v2s16(0,0));
2012
2013         // Initially write whole map
2014         save(false);
2015 }
2016
2017 ServerMap::~ServerMap()
2018 {
2019         infostream<<__FUNCTION_NAME<<std::endl;
2020
2021         try
2022         {
2023                 if(m_map_saving_enabled)
2024                 {
2025                         // Save only changed parts
2026                         save(true);
2027                         infostream<<"Server: saved map to "<<m_savedir<<std::endl;
2028                 }
2029                 else
2030                 {
2031                         infostream<<"Server: map not saved"<<std::endl;
2032                 }
2033         }
2034         catch(std::exception &e)
2035         {
2036                 infostream<<"Server: Failed to save map to "<<m_savedir
2037                                 <<", exception: "<<e.what()<<std::endl;
2038         }
2039
2040         /*
2041                 Close database if it was opened
2042         */
2043         if(m_database_read)
2044                 sqlite3_finalize(m_database_read);
2045         if(m_database_write)
2046                 sqlite3_finalize(m_database_write);
2047         if(m_database)
2048                 sqlite3_close(m_database);
2049
2050 #if 0
2051         /*
2052                 Free all MapChunks
2053         */
2054         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2055         for(; i.atEnd() == false; i++)
2056         {
2057                 MapChunk *chunk = i.getNode()->getValue();
2058                 delete chunk;
2059         }
2060 #endif
2061 }
2062
2063 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2064 {
2065         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2066         if(enable_mapgen_debug_info)
2067                 infostream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2068                                 <<blockpos.Z<<")"<<std::endl;
2069         
2070         // Do nothing if not inside limits (+-1 because of neighbors)
2071         if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
2072                 blockpos_over_limit(blockpos + v3s16(1,1,1)))
2073         {
2074                 data->no_op = true;
2075                 return;
2076         }
2077         
2078         data->no_op = false;
2079         data->seed = m_seed;
2080         data->blockpos = blockpos;
2081
2082         /*
2083                 Create the whole area of this and the neighboring blocks
2084         */
2085         {
2086                 //TimeTaker timer("initBlockMake() create area");
2087                 
2088                 for(s16 x=-1; x<=1; x++)
2089                 for(s16 z=-1; z<=1; z++)
2090                 {
2091                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2092                         // Sector metadata is loaded from disk if not already loaded.
2093                         ServerMapSector *sector = createSector(sectorpos);
2094                         assert(sector);
2095
2096                         for(s16 y=-1; y<=1; y++)
2097                         {
2098                                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2099                                 //MapBlock *block = createBlock(p);
2100                                 // 1) get from memory, 2) load from disk
2101                                 MapBlock *block = emergeBlock(p, false);
2102                                 // 3) create a blank one
2103                                 if(block == NULL)
2104                                 {
2105                                         block = createBlock(p);
2106
2107                                         /*
2108                                                 Block gets sunlight if this is true.
2109
2110                                                 Refer to the map generator heuristics.
2111                                         */
2112                                         bool ug = mapgen::block_is_underground(data->seed, p);
2113                                         block->setIsUnderground(ug);
2114                                 }
2115
2116                                 // Lighting will not be valid after make_chunk is called
2117                                 block->setLightingExpired(true);
2118                                 // Lighting will be calculated
2119                                 //block->setLightingExpired(false);
2120                         }
2121                 }
2122         }
2123         
2124         /*
2125                 Now we have a big empty area.
2126
2127                 Make a ManualMapVoxelManipulator that contains this and the
2128                 neighboring blocks
2129         */
2130         
2131         // The area that contains this block and it's neighbors
2132         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2133         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2134         
2135         data->vmanip = new ManualMapVoxelManipulator(this);
2136         //data->vmanip->setMap(this);
2137
2138         // Add the area
2139         {
2140                 //TimeTaker timer("initBlockMake() initialEmerge");
2141                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2142         }
2143
2144         // Data is ready now.
2145 }
2146
2147 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2148                 core::map<v3s16, MapBlock*> &changed_blocks)
2149 {
2150         v3s16 blockpos = data->blockpos;
2151         /*infostream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2152                         <<blockpos.Z<<")"<<std::endl;*/
2153
2154         if(data->no_op)
2155         {
2156                 //infostream<<"finishBlockMake(): no-op"<<std::endl;
2157                 return NULL;
2158         }
2159
2160         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2161
2162         /*infostream<<"Resulting vmanip:"<<std::endl;
2163         data->vmanip.print(infostream);*/
2164         
2165         /*
2166                 Blit generated stuff to map
2167                 NOTE: blitBackAll adds nearly everything to changed_blocks
2168         */
2169         {
2170                 // 70ms @cs=8
2171                 //TimeTaker timer("finishBlockMake() blitBackAll");
2172                 data->vmanip->blitBackAll(&changed_blocks);
2173         }
2174
2175         if(enable_mapgen_debug_info)
2176                 infostream<<"finishBlockMake: changed_blocks.size()="
2177                                 <<changed_blocks.size()<<std::endl;
2178
2179         /*
2180                 Copy transforming liquid information
2181         */
2182         while(data->transforming_liquid.size() > 0)
2183         {
2184                 v3s16 p = data->transforming_liquid.pop_front();
2185                 m_transforming_liquid.push_back(p);
2186         }
2187         
2188         /*
2189                 Get central block
2190         */
2191         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2192         assert(block);
2193
2194         /*
2195                 Set is_underground flag for lighting with sunlight.
2196
2197                 Refer to map generator heuristics.
2198
2199                 NOTE: This is done in initChunkMake
2200         */
2201         //block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2202
2203
2204         /*
2205                 Add sunlight to central block.
2206                 This makes in-dark-spawning monsters to not flood the whole thing.
2207                 Do not spread the light, though.
2208         */
2209         /*core::map<v3s16, bool> light_sources;
2210         bool black_air_left = false;
2211         block->propagateSunlight(light_sources, true, &black_air_left);*/
2212
2213         /*
2214                 NOTE: Lighting and object adding shouldn't really be here, but
2215                 lighting is a bit tricky to move properly to makeBlock.
2216                 TODO: Do this the right way anyway, that is, move it to makeBlock.
2217                       - There needs to be some way for makeBlock to report back if
2218                             the lighting update is going further down because of the
2219                                 new block blocking light
2220         */
2221
2222         /*
2223                 Update lighting
2224                 NOTE: This takes ~60ms, TODO: Investigate why
2225         */
2226         {
2227                 TimeTaker t("finishBlockMake lighting update");
2228
2229                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2230 #if 1
2231                 // Center block
2232                 lighting_update_blocks.insert(block->getPos(), block);
2233
2234                 /*{
2235                         s16 x = 0;
2236                         s16 z = 0;
2237                         v3s16 p = block->getPos()+v3s16(x,1,z);
2238                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2239                 }*/
2240 #endif
2241 #if 0
2242                 // All modified blocks
2243                 // NOTE: Should this be done? If this is not done, then the lighting
2244                 // of the others will be updated in a different place, one by one, i
2245                 // think... or they might not? Well, at least they are left marked as
2246                 // "lighting expired"; it seems that is not handled at all anywhere,
2247                 // so enabling this will slow it down A LOT because otherwise it
2248                 // would not do this at all. This causes the black trees.
2249                 for(core::map<v3s16, MapBlock*>::Iterator
2250                                 i = changed_blocks.getIterator();
2251                                 i.atEnd() == false; i++)
2252                 {
2253                         lighting_update_blocks.insert(i.getNode()->getKey(),
2254                                         i.getNode()->getValue());
2255                 }
2256                 /*// Also force-add all the upmost blocks for proper sunlight
2257                 for(s16 x=-1; x<=1; x++)
2258                 for(s16 z=-1; z<=1; z++)
2259                 {
2260                         v3s16 p = block->getPos()+v3s16(x,1,z);
2261                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2262                 }*/
2263 #endif
2264                 updateLighting(lighting_update_blocks, changed_blocks);
2265                 
2266                 /*
2267                         Set lighting to non-expired state in all of them.
2268                         This is cheating, but it is not fast enough if all of them
2269                         would actually be updated.
2270                 */
2271                 for(s16 x=-1; x<=1; x++)
2272                 for(s16 y=-1; y<=1; y++)
2273                 for(s16 z=-1; z<=1; z++)
2274                 {
2275                         v3s16 p = block->getPos()+v3s16(x,y,z);
2276                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2277                 }
2278
2279                 if(enable_mapgen_debug_info == false)
2280                         t.stop(true); // Hide output
2281         }
2282
2283         /*
2284                 Add random objects to block
2285         */
2286         mapgen::add_random_objects(block);
2287
2288         /*
2289                 Go through changed blocks
2290         */
2291         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2292                         i.atEnd() == false; i++)
2293         {
2294                 MapBlock *block = i.getNode()->getValue();
2295                 assert(block);
2296                 /*
2297                         Update day/night difference cache of the MapBlocks
2298                 */
2299                 block->updateDayNightDiff();
2300                 /*
2301                         Set block as modified
2302                 */
2303                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2304         }
2305
2306         /*
2307                 Set central block as generated
2308         */
2309         block->setGenerated(true);
2310         
2311         /*
2312                 Save changed parts of map
2313                 NOTE: Will be saved later.
2314         */
2315         //save(true);
2316
2317         /*infostream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2318                         <<blockpos.Z<<")"<<std::endl;*/
2319 #if 0
2320         if(enable_mapgen_debug_info)
2321         {
2322                 /*
2323                         Analyze resulting blocks
2324                 */
2325                 for(s16 x=-1; x<=1; x++)
2326                 for(s16 y=-1; y<=1; y++)
2327                 for(s16 z=-1; z<=1; z++)
2328                 {
2329                         v3s16 p = block->getPos()+v3s16(x,y,z);
2330                         MapBlock *block = getBlockNoCreateNoEx(p);
2331                         char spos[20];
2332                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2333                         infostream<<"Generated "<<spos<<": "
2334                                         <<analyze_block(block)<<std::endl;
2335                 }
2336         }
2337 #endif
2338
2339         return block;
2340 }
2341
2342 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2343 {
2344         DSTACKF("%s: p2d=(%d,%d)",
2345                         __FUNCTION_NAME,
2346                         p2d.X, p2d.Y);
2347         
2348         /*
2349                 Check if it exists already in memory
2350         */
2351         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2352         if(sector != NULL)
2353                 return sector;
2354         
2355         /*
2356                 Try to load it from disk (with blocks)
2357         */
2358         //if(loadSectorFull(p2d) == true)
2359
2360         /*
2361                 Try to load metadata from disk
2362         */
2363 #if 0
2364         if(loadSectorMeta(p2d) == true)
2365         {
2366                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2367                 if(sector == NULL)
2368                 {
2369                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2370                         throw InvalidPositionException("");
2371                 }
2372                 return sector;
2373         }
2374 #endif
2375         /*
2376                 Do not create over-limit
2377         */
2378         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2379         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2380         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2381         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2382                 throw InvalidPositionException("createSector(): pos. over limit");
2383
2384         /*
2385                 Generate blank sector
2386         */
2387         
2388         sector = new ServerMapSector(this, p2d);
2389         
2390         // Sector position on map in nodes
2391         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2392
2393         /*
2394                 Insert to container
2395         */
2396         m_sectors.insert(p2d, sector);
2397         
2398         return sector;
2399 }
2400
2401 /*
2402         This is a quick-hand function for calling makeBlock().
2403 */
2404 MapBlock * ServerMap::generateBlock(
2405                 v3s16 p,
2406                 core::map<v3s16, MapBlock*> &modified_blocks
2407 )
2408 {
2409         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2410         
2411         /*infostream<<"generateBlock(): "
2412                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2413                         <<std::endl;*/
2414         
2415         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2416
2417         TimeTaker timer("generateBlock");
2418         
2419         //MapBlock *block = original_dummy;
2420                         
2421         v2s16 p2d(p.X, p.Z);
2422         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2423         
2424         /*
2425                 Do not generate over-limit
2426         */
2427         if(blockpos_over_limit(p))
2428         {
2429                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2430                 throw InvalidPositionException("generateBlock(): pos. over limit");
2431         }
2432
2433         /*
2434                 Create block make data
2435         */
2436         mapgen::BlockMakeData data;
2437         initBlockMake(&data, p);
2438
2439         /*
2440                 Generate block
2441         */
2442         {
2443                 TimeTaker t("mapgen::make_block()");
2444                 mapgen::make_block(&data);
2445
2446                 if(enable_mapgen_debug_info == false)
2447                         t.stop(true); // Hide output
2448         }
2449
2450         /*
2451                 Blit data back on map, update lighting, add mobs and whatever this does
2452         */
2453         finishBlockMake(&data, modified_blocks);
2454
2455         /*
2456                 Get central block
2457         */
2458         MapBlock *block = getBlockNoCreateNoEx(p);
2459
2460 #if 0
2461         /*
2462                 Check result
2463         */
2464         if(block)
2465         {
2466                 bool erroneus_content = false;
2467                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2468                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2469                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2470                 {
2471                         v3s16 p(x0,y0,z0);
2472                         MapNode n = block->getNode(p);
2473                         if(n.getContent() == CONTENT_IGNORE)
2474                         {
2475                                 infostream<<"CONTENT_IGNORE at "
2476                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2477                                                 <<std::endl;
2478                                 erroneus_content = true;
2479                                 assert(0);
2480                         }
2481                 }
2482                 if(erroneus_content)
2483                 {
2484                         assert(0);
2485                 }
2486         }
2487 #endif
2488
2489 #if 0
2490         /*
2491                 Generate a completely empty block
2492         */
2493         if(block)
2494         {
2495                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2496                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2497                 {
2498                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2499                         {
2500                                 MapNode n;
2501                                 if(y0%2==0)
2502                                         n.setContent(CONTENT_AIR);
2503                                 else
2504                                         n.setContent(CONTENT_STONE);
2505                                 block->setNode(v3s16(x0,y0,z0), n);
2506                         }
2507                 }
2508         }
2509 #endif
2510
2511         if(enable_mapgen_debug_info == false)
2512                 timer.stop(true); // Hide output
2513
2514         return block;
2515 }
2516
2517 MapBlock * ServerMap::createBlock(v3s16 p)
2518 {
2519         DSTACKF("%s: p=(%d,%d,%d)",
2520                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2521         
2522         /*
2523                 Do not create over-limit
2524         */
2525         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2526         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2527         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2528         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2529         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2530         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2531                 throw InvalidPositionException("createBlock(): pos. over limit");
2532         
2533         v2s16 p2d(p.X, p.Z);
2534         s16 block_y = p.Y;
2535         /*
2536                 This will create or load a sector if not found in memory.
2537                 If block exists on disk, it will be loaded.
2538
2539                 NOTE: On old save formats, this will be slow, as it generates
2540                       lighting on blocks for them.
2541         */
2542         ServerMapSector *sector;
2543         try{
2544                 sector = (ServerMapSector*)createSector(p2d);
2545                 assert(sector->getId() == MAPSECTOR_SERVER);
2546         }
2547         catch(InvalidPositionException &e)
2548         {
2549                 infostream<<"createBlock: createSector() failed"<<std::endl;
2550                 throw e;
2551         }
2552         /*
2553                 NOTE: This should not be done, or at least the exception
2554                 should not be passed on as std::exception, because it
2555                 won't be catched at all.
2556         */
2557         /*catch(std::exception &e)
2558         {
2559                 infostream<<"createBlock: createSector() failed: "
2560                                 <<e.what()<<std::endl;
2561                 throw e;
2562         }*/
2563
2564         /*
2565                 Try to get a block from the sector
2566         */
2567
2568         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2569         if(block)
2570         {
2571                 if(block->isDummy())
2572                         block->unDummify();
2573                 return block;
2574         }
2575         // Create blank
2576         block = sector->createBlankBlock(block_y);
2577         return block;
2578 }
2579
2580 MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
2581 {
2582         DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
2583                         __FUNCTION_NAME,
2584                         p.X, p.Y, p.Z, allow_generate);
2585         
2586         {
2587                 MapBlock *block = getBlockNoCreateNoEx(p);
2588                 if(block && block->isDummy() == false)
2589                         return block;
2590         }
2591
2592         {
2593                 MapBlock *block = loadBlock(p);
2594                 if(block)
2595                         return block;
2596         }
2597
2598         if(allow_generate)
2599         {
2600                 core::map<v3s16, MapBlock*> modified_blocks;
2601                 MapBlock *block = generateBlock(p, modified_blocks);
2602                 if(block)
2603                 {
2604                         MapEditEvent event;
2605                         event.type = MEET_OTHER;
2606                         event.p = p;
2607
2608                         // Copy modified_blocks to event
2609                         for(core::map<v3s16, MapBlock*>::Iterator
2610                                         i = modified_blocks.getIterator();
2611                                         i.atEnd()==false; i++)
2612                         {
2613                                 event.modified_blocks.insert(i.getNode()->getKey(), false);
2614                         }
2615
2616                         // Queue event
2617                         dispatchEvent(&event);
2618                                                                 
2619                         return block;
2620                 }
2621         }
2622
2623         return NULL;
2624 }
2625
2626 s16 ServerMap::findGroundLevel(v2s16 p2d)
2627 {
2628 #if 0
2629         /*
2630                 Uh, just do something random...
2631         */
2632         // Find existing map from top to down
2633         s16 max=63;
2634         s16 min=-64;
2635         v3s16 p(p2d.X, max, p2d.Y);
2636         for(; p.Y>min; p.Y--)
2637         {
2638                 MapNode n = getNodeNoEx(p);
2639                 if(n.getContent() != CONTENT_IGNORE)
2640                         break;
2641         }
2642         if(p.Y == min)
2643                 goto plan_b;
2644         // If this node is not air, go to plan b
2645         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2646                 goto plan_b;
2647         // Search existing walkable and return it
2648         for(; p.Y>min; p.Y--)
2649         {
2650                 MapNode n = getNodeNoEx(p);
2651                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2652                         return p.Y;
2653         }
2654
2655         // Move to plan b
2656 plan_b:
2657 #endif
2658
2659         /*
2660                 Determine from map generator noise functions
2661         */
2662         
2663         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2664         return level;
2665
2666         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2667         //return (s16)level;
2668 }
2669
2670 void ServerMap::createDatabase() {
2671         int e;
2672         assert(m_database);
2673         e = sqlite3_exec(m_database,
2674                 "CREATE TABLE IF NOT EXISTS `blocks` ("
2675                         "`pos` INT NOT NULL PRIMARY KEY,"
2676                         "`data` BLOB"
2677                 ");"
2678         , NULL, NULL, NULL);
2679         if(e == SQLITE_ABORT)
2680                 throw FileNotGoodException("Could not create database structure");
2681         else
2682                 infostream<<"Server: Database structure was created";
2683 }
2684
2685 void ServerMap::verifyDatabase() {
2686         if(m_database)
2687                 return;
2688         
2689         {
2690                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
2691                 bool needs_create = false;
2692                 int d;
2693                 
2694                 /*
2695                         Open the database connection
2696                 */
2697         
2698                 createDirs(m_savedir);
2699         
2700                 if(!fs::PathExists(dbp))
2701                         needs_create = true;
2702         
2703                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
2704                 if(d != SQLITE_OK) {
2705                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
2706                         throw FileNotGoodException("Cannot open database file");
2707                 }
2708                 
2709                 if(needs_create)
2710                         createDatabase();
2711         
2712                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
2713                 if(d != SQLITE_OK) {
2714                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2715                         throw FileNotGoodException("Cannot prepare read statement");
2716                 }
2717                 
2718                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
2719                 if(d != SQLITE_OK) {
2720                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2721                         throw FileNotGoodException("Cannot prepare write statement");
2722                 }
2723                 
2724                 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
2725                 if(d != SQLITE_OK) {
2726                         infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2727                         throw FileNotGoodException("Cannot prepare read statement");
2728                 }
2729                 
2730                 infostream<<"Server: Database opened"<<std::endl;
2731         }
2732 }
2733
2734 bool ServerMap::loadFromFolders() {
2735         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2736                 return true;
2737         return false;
2738 }
2739
2740 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
2741         return (sqlite3_int64)pos.Z*16777216 +
2742                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
2743 }
2744
2745 void ServerMap::createDirs(std::string path)
2746 {
2747         if(fs::CreateAllDirs(path) == false)
2748         {
2749                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2750                                 <<"\""<<path<<"\""<<std::endl;
2751                 throw BaseException("ServerMap failed to create directory");
2752         }
2753 }
2754
2755 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2756 {
2757         char cc[9];
2758         switch(layout)
2759         {
2760                 case 1:
2761                         snprintf(cc, 9, "%.4x%.4x",
2762                                 (unsigned int)pos.X&0xffff,
2763                                 (unsigned int)pos.Y&0xffff);
2764
2765                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2766                 case 2:
2767                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2768                                 (unsigned int)pos.X&0xfff,
2769                                 (unsigned int)pos.Y&0xfff);
2770
2771                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2772                 default:
2773                         assert(false);
2774         }
2775 }
2776
2777 v2s16 ServerMap::getSectorPos(std::string dirname)
2778 {
2779         unsigned int x, y;
2780         int r;
2781         size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
2782         assert(spos != std::string::npos);
2783         if(dirname.size() - spos == 8)
2784         {
2785                 // Old layout
2786                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2787         }
2788         else if(dirname.size() - spos == 3)
2789         {
2790                 // New layout
2791                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2792                 // Sign-extend the 12 bit values up to 16 bits...
2793                 if(x&0x800) x|=0xF000;
2794                 if(y&0x800) y|=0xF000;
2795         }
2796         else
2797         {
2798                 assert(false);
2799         }
2800         assert(r == 2);
2801         v2s16 pos((s16)x, (s16)y);
2802         return pos;
2803 }
2804
2805 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2806 {
2807         v2s16 p2d = getSectorPos(sectordir);
2808
2809         if(blockfile.size() != 4){
2810                 throw InvalidFilenameException("Invalid block filename");
2811         }
2812         unsigned int y;
2813         int r = sscanf(blockfile.c_str(), "%4x", &y);
2814         if(r != 1)
2815                 throw InvalidFilenameException("Invalid block filename");
2816         return v3s16(p2d.X, y, p2d.Y);
2817 }
2818
2819 std::string ServerMap::getBlockFilename(v3s16 p)
2820 {
2821         char cc[5];
2822         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2823         return cc;
2824 }
2825
2826 void ServerMap::save(bool only_changed)
2827 {
2828         DSTACK(__FUNCTION_NAME);
2829         if(m_map_saving_enabled == false)
2830         {
2831                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2832                 return;
2833         }
2834         
2835         if(only_changed == false)
2836                 infostream<<"ServerMap: Saving whole map, this can take time."
2837                                 <<std::endl;
2838         
2839         if(only_changed == false || m_map_metadata_changed)
2840         {
2841                 saveMapMeta();
2842         }
2843
2844         u32 sector_meta_count = 0;
2845         u32 block_count = 0;
2846         u32 block_count_all = 0; // Number of blocks in memory
2847         
2848         beginSave();
2849         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2850         for(; i.atEnd() == false; i++)
2851         {
2852                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2853                 assert(sector->getId() == MAPSECTOR_SERVER);
2854         
2855                 if(sector->differs_from_disk || only_changed == false)
2856                 {
2857                         saveSectorMeta(sector);
2858                         sector_meta_count++;
2859                 }
2860                 core::list<MapBlock*> blocks;
2861                 sector->getBlocks(blocks);
2862                 core::list<MapBlock*>::Iterator j;
2863                 
2864                 //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL);
2865                 for(j=blocks.begin(); j!=blocks.end(); j++)
2866                 {
2867                         MapBlock *block = *j;
2868                         
2869                         block_count_all++;
2870
2871                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
2872                                         || only_changed == false)
2873                         {
2874                                 saveBlock(block);
2875                                 block_count++;
2876
2877                                 /*infostream<<"ServerMap: Written block ("
2878                                                 <<block->getPos().X<<","
2879                                                 <<block->getPos().Y<<","
2880                                                 <<block->getPos().Z<<")"
2881                                                 <<std::endl;*/
2882                         }
2883                 //sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL);
2884                 }
2885         }
2886         endSave();
2887
2888         /*
2889                 Only print if something happened or saved whole map
2890         */
2891         if(only_changed == false || sector_meta_count != 0
2892                         || block_count != 0)
2893         {
2894                 infostream<<"ServerMap: Written: "
2895                                 <<sector_meta_count<<" sector metadata files, "
2896                                 <<block_count<<" block files"
2897                                 <<", "<<block_count_all<<" blocks in memory."
2898                                 <<std::endl;
2899         }
2900 }
2901
2902 static s32 unsignedToSigned(s32 i, s32 max_positive)
2903 {
2904         if(i < max_positive)
2905                 return i;
2906         else
2907                 return i - 2*max_positive;
2908 }
2909
2910 // modulo of a negative number does not work consistently in C
2911 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
2912 {
2913         if(i >= 0)
2914                 return i % mod;
2915         return mod - ((-i) % mod);
2916 }
2917
2918 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
2919 {
2920         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2921         i = (i - x) / 4096;
2922         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2923         i = (i - y) / 4096;
2924         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2925         return v3s16(x,y,z);
2926 }
2927
2928 void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
2929 {
2930         if(loadFromFolders()){
2931                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
2932                                 <<"all blocks that are stored in flat files"<<std::endl;
2933         }
2934         
2935         {
2936                 verifyDatabase();
2937                 
2938                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
2939                 {
2940                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
2941                         v3s16 p = getIntegerAsBlock(block_i);
2942                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
2943                         dst.push_back(p);
2944                 }
2945         }
2946 }
2947
2948 void ServerMap::saveMapMeta()
2949 {
2950         DSTACK(__FUNCTION_NAME);
2951         
2952         infostream<<"ServerMap::saveMapMeta(): "
2953                         <<"seed="<<m_seed
2954                         <<std::endl;
2955
2956         createDirs(m_savedir);
2957         
2958         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
2959         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
2960         if(os.good() == false)
2961         {
2962                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
2963                                 <<"could not open"<<fullpath<<std::endl;
2964                 throw FileNotGoodException("Cannot open chunk metadata");
2965         }
2966         
2967         Settings params;
2968         params.setU64("seed", m_seed);
2969
2970         params.writeLines(os);
2971
2972         os<<"[end_of_params]\n";
2973         
2974         m_map_metadata_changed = false;
2975 }
2976
2977 void ServerMap::loadMapMeta()
2978 {
2979         DSTACK(__FUNCTION_NAME);
2980         
2981         infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
2982                         <<std::endl;
2983
2984         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
2985         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2986         if(is.good() == false)
2987         {
2988                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
2989                                 <<"could not open"<<fullpath<<std::endl;
2990                 throw FileNotGoodException("Cannot open map metadata");
2991         }
2992
2993         Settings params;
2994
2995         for(;;)
2996         {
2997                 if(is.eof())
2998                         throw SerializationError
2999                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3000                 std::string line;
3001                 std::getline(is, line);
3002                 std::string trimmedline = trim(line);
3003                 if(trimmedline == "[end_of_params]")
3004                         break;
3005                 params.parseConfigLine(line);
3006         }
3007
3008         m_seed = params.getU64("seed");
3009
3010         infostream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3011 }
3012
3013 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3014 {
3015         DSTACK(__FUNCTION_NAME);
3016         // Format used for writing
3017         u8 version = SER_FMT_VER_HIGHEST;
3018         // Get destination
3019         v2s16 pos = sector->getPos();
3020         std::string dir = getSectorDir(pos);
3021         createDirs(dir);
3022         
3023         std::string fullpath = dir + DIR_DELIM + "meta";
3024         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3025         if(o.good() == false)
3026                 throw FileNotGoodException("Cannot open sector metafile");
3027
3028         sector->serialize(o, version);
3029         
3030         sector->differs_from_disk = false;
3031 }
3032
3033 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3034 {
3035         DSTACK(__FUNCTION_NAME);
3036         // Get destination
3037         v2s16 p2d = getSectorPos(sectordir);
3038
3039         ServerMapSector *sector = NULL;
3040
3041         std::string fullpath = sectordir + DIR_DELIM + "meta";
3042         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3043         if(is.good() == false)
3044         {
3045                 // If the directory exists anyway, it probably is in some old
3046                 // format. Just go ahead and create the sector.
3047                 if(fs::PathExists(sectordir))
3048                 {
3049                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3050                                         <<fullpath<<" doesn't exist but directory does."
3051                                         <<" Continuing with a sector with no metadata."
3052                                         <<std::endl;*/
3053                         sector = new ServerMapSector(this, p2d);
3054                         m_sectors.insert(p2d, sector);
3055                 }
3056                 else
3057                 {
3058                         throw FileNotGoodException("Cannot open sector metafile");
3059                 }
3060         }
3061         else
3062         {
3063                 sector = ServerMapSector::deSerialize
3064                                 (is, this, p2d, m_sectors);
3065                 if(save_after_load)
3066                         saveSectorMeta(sector);
3067         }
3068         
3069         sector->differs_from_disk = false;
3070
3071         return sector;
3072 }
3073
3074 bool ServerMap::loadSectorMeta(v2s16 p2d)
3075 {
3076         DSTACK(__FUNCTION_NAME);
3077
3078         MapSector *sector = NULL;
3079
3080         // The directory layout we're going to load from.
3081         //  1 - original sectors/xxxxzzzz/
3082         //  2 - new sectors2/xxx/zzz/
3083         //  If we load from anything but the latest structure, we will
3084         //  immediately save to the new one, and remove the old.
3085         int loadlayout = 1;
3086         std::string sectordir1 = getSectorDir(p2d, 1);
3087         std::string sectordir;
3088         if(fs::PathExists(sectordir1))
3089         {
3090                 sectordir = sectordir1;
3091         }
3092         else
3093         {
3094                 loadlayout = 2;
3095                 sectordir = getSectorDir(p2d, 2);
3096         }
3097
3098         try{
3099                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3100         }
3101         catch(InvalidFilenameException &e)
3102         {
3103                 return false;
3104         }
3105         catch(FileNotGoodException &e)
3106         {
3107                 return false;
3108         }
3109         catch(std::exception &e)
3110         {
3111                 return false;
3112         }
3113         
3114         return true;
3115 }
3116
3117 #if 0
3118 bool ServerMap::loadSectorFull(v2s16 p2d)
3119 {
3120         DSTACK(__FUNCTION_NAME);
3121
3122         MapSector *sector = NULL;
3123
3124         // The directory layout we're going to load from.
3125         //  1 - original sectors/xxxxzzzz/
3126         //  2 - new sectors2/xxx/zzz/
3127         //  If we load from anything but the latest structure, we will
3128         //  immediately save to the new one, and remove the old.
3129         int loadlayout = 1;
3130         std::string sectordir1 = getSectorDir(p2d, 1);
3131         std::string sectordir;
3132         if(fs::PathExists(sectordir1))
3133         {
3134                 sectordir = sectordir1;
3135         }
3136         else
3137         {
3138                 loadlayout = 2;
3139                 sectordir = getSectorDir(p2d, 2);
3140         }
3141
3142         try{
3143                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3144         }
3145         catch(InvalidFilenameException &e)
3146         {
3147                 return false;
3148         }
3149         catch(FileNotGoodException &e)
3150         {
3151                 return false;
3152         }
3153         catch(std::exception &e)
3154         {
3155                 return false;
3156         }
3157         
3158         /*
3159                 Load blocks
3160         */
3161         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3162                         (sectordir);
3163         std::vector<fs::DirListNode>::iterator i2;
3164         for(i2=list2.begin(); i2!=list2.end(); i2++)
3165         {
3166                 // We want files
3167                 if(i2->dir)
3168                         continue;
3169                 try{
3170                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3171                 }
3172                 catch(InvalidFilenameException &e)
3173                 {
3174                         // This catches unknown crap in directory
3175                 }
3176         }
3177
3178         if(loadlayout != 2)
3179         {
3180                 infostream<<"Sector converted to new layout - deleting "<<
3181                         sectordir1<<std::endl;
3182                 fs::RecursiveDelete(sectordir1);
3183         }
3184
3185         return true;
3186 }
3187 #endif
3188
3189 void ServerMap::beginSave() {
3190         verifyDatabase();
3191         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3192                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3193 }
3194
3195 void ServerMap::endSave() {
3196         verifyDatabase();
3197         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3198                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3199 }
3200
3201 void ServerMap::saveBlock(MapBlock *block)
3202 {
3203         DSTACK(__FUNCTION_NAME);
3204         /*
3205                 Dummy blocks are not written
3206         */
3207         if(block->isDummy())
3208         {
3209                 /*v3s16 p = block->getPos();
3210                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3211                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3212                 return;
3213         }
3214
3215         // Format used for writing
3216         u8 version = SER_FMT_VER_HIGHEST;
3217         // Get destination
3218         v3s16 p3d = block->getPos();
3219         
3220         
3221 #if 0
3222         v2s16 p2d(p3d.X, p3d.Z);
3223         std::string sectordir = getSectorDir(p2d);
3224
3225         createDirs(sectordir);
3226
3227         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3228         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3229         if(o.good() == false)
3230                 throw FileNotGoodException("Cannot open block data");
3231 #endif
3232         /*
3233                 [0] u8 serialization version
3234                 [1] data
3235         */
3236         
3237         verifyDatabase();
3238         
3239         std::ostringstream o(std::ios_base::binary);
3240         
3241         o.write((char*)&version, 1);
3242         
3243         // Write basic data
3244         block->serialize(o, version);
3245         
3246         // Write extra data stored on disk
3247         block->serializeDiskExtra(o, version);
3248         
3249         // Write block to database
3250         
3251         std::string tmp = o.str();
3252         const char *bytes = tmp.c_str();
3253         
3254         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
3255                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3256         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
3257                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3258         int written = sqlite3_step(m_database_write);
3259         if(written != SQLITE_DONE)
3260                 infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3261                 <<sqlite3_errmsg(m_database)<<std::endl;
3262         // Make ready for later reuse
3263         sqlite3_reset(m_database_write);
3264         
3265         // We just wrote it to the disk so clear modified flag
3266         block->resetModified();
3267 }
3268
3269 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3270 {
3271         DSTACK(__FUNCTION_NAME);
3272
3273         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3274         try{
3275
3276                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3277                 if(is.good() == false)
3278                         throw FileNotGoodException("Cannot open block file");
3279                 
3280                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3281                 v2s16 p2d(p3d.X, p3d.Z);
3282                 
3283                 assert(sector->getPos() == p2d);
3284                 
3285                 u8 version = SER_FMT_VER_INVALID;
3286                 is.read((char*)&version, 1);
3287
3288                 if(is.fail())
3289                         throw SerializationError("ServerMap::loadBlock(): Failed"
3290                                         " to read MapBlock version");
3291
3292                 /*u32 block_size = MapBlock::serializedLength(version);
3293                 SharedBuffer<u8> data(block_size);
3294                 is.read((char*)*data, block_size);*/
3295
3296                 // This will always return a sector because we're the server
3297                 //MapSector *sector = emergeSector(p2d);
3298
3299                 MapBlock *block = NULL;
3300                 bool created_new = false;
3301                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3302                 if(block == NULL)
3303                 {
3304                         block = sector->createBlankBlockNoInsert(p3d.Y);
3305                         created_new = true;
3306                 }
3307                 
3308                 // Read basic data
3309                 block->deSerialize(is, version);
3310
3311                 // Read extra data stored on disk
3312                 block->deSerializeDiskExtra(is, version);
3313                 
3314                 // If it's a new block, insert it to the map
3315                 if(created_new)
3316                         sector->insertBlock(block);
3317                 
3318                 /*
3319                         Save blocks loaded in old format in new format
3320                 */
3321
3322                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3323                 {
3324                         saveBlock(block);
3325                         
3326                         // Should be in database now, so delete the old file
3327                         fs::RecursiveDelete(fullpath);
3328                 }
3329                 
3330                 // We just loaded it from the disk, so it's up-to-date.
3331                 block->resetModified();
3332
3333         }
3334         catch(SerializationError &e)
3335         {
3336                 infostream<<"WARNING: Invalid block data on disk "
3337                                 <<"fullpath="<<fullpath
3338                                 <<" (SerializationError). "
3339                                 <<"what()="<<e.what()
3340                                 <<std::endl;
3341                                 //" Ignoring. A new one will be generated.
3342                 assert(0);
3343
3344                 // TODO: Backup file; name is in fullpath.
3345         }
3346 }
3347
3348 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3349 {
3350         DSTACK(__FUNCTION_NAME);
3351
3352         try {
3353                 std::istringstream is(*blob, std::ios_base::binary);
3354                 
3355                 u8 version = SER_FMT_VER_INVALID;
3356                 is.read((char*)&version, 1);
3357
3358                 if(is.fail())
3359                         throw SerializationError("ServerMap::loadBlock(): Failed"
3360                                         " to read MapBlock version");
3361
3362                 /*u32 block_size = MapBlock::serializedLength(version);
3363                 SharedBuffer<u8> data(block_size);
3364                 is.read((char*)*data, block_size);*/
3365
3366                 // This will always return a sector because we're the server
3367                 //MapSector *sector = emergeSector(p2d);
3368
3369                 MapBlock *block = NULL;
3370                 bool created_new = false;
3371                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3372                 if(block == NULL)
3373                 {
3374                         block = sector->createBlankBlockNoInsert(p3d.Y);
3375                         created_new = true;
3376                 }
3377                 
3378                 // Read basic data
3379                 block->deSerialize(is, version);
3380
3381                 // Read extra data stored on disk
3382                 block->deSerializeDiskExtra(is, version);
3383                 
3384                 // If it's a new block, insert it to the map
3385                 if(created_new)
3386                         sector->insertBlock(block);
3387                 
3388                 /*
3389                         Save blocks loaded in old format in new format
3390                 */
3391
3392                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3393                 {
3394                         saveBlock(block);
3395                 }
3396                 
3397                 // We just loaded it from, so it's up-to-date.
3398                 block->resetModified();
3399
3400         }
3401         catch(SerializationError &e)
3402         {
3403                 infostream<<"WARNING: Invalid block data in database "
3404                                 <<" (SerializationError). "
3405                                 <<"what()="<<e.what()
3406                                 <<std::endl;
3407                                 //" Ignoring. A new one will be generated.
3408                 assert(0);
3409
3410                 // TODO: Copy to a backup database.
3411         }
3412 }
3413
3414 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3415 {
3416         DSTACK(__FUNCTION_NAME);
3417
3418         v2s16 p2d(blockpos.X, blockpos.Z);
3419
3420         if(!loadFromFolders()) {
3421                 verifyDatabase();
3422                 
3423                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3424                         infostream<<"WARNING: Could not bind block position for load: "
3425                                 <<sqlite3_errmsg(m_database)<<std::endl;
3426                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3427                         /*
3428                                 Make sure sector is loaded
3429                         */
3430                         MapSector *sector = createSector(p2d);
3431                         
3432                         /*
3433                                 Load block
3434                         */
3435                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3436                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3437                         
3438                         std::string datastr(data, len);
3439                         
3440                         loadBlock(&datastr, blockpos, sector, false);
3441
3442                         sqlite3_step(m_database_read);
3443                         // We should never get more than 1 row, so ok to reset
3444                         sqlite3_reset(m_database_read);
3445
3446                         return getBlockNoCreateNoEx(blockpos);
3447                 }
3448                 sqlite3_reset(m_database_read);
3449                 
3450                 // Not found in database, try the files
3451         }
3452
3453         // The directory layout we're going to load from.
3454         //  1 - original sectors/xxxxzzzz/
3455         //  2 - new sectors2/xxx/zzz/
3456         //  If we load from anything but the latest structure, we will
3457         //  immediately save to the new one, and remove the old.
3458         int loadlayout = 1;
3459         std::string sectordir1 = getSectorDir(p2d, 1);
3460         std::string sectordir;
3461         if(fs::PathExists(sectordir1))
3462         {
3463                 sectordir = sectordir1;
3464         }
3465         else
3466         {
3467                 loadlayout = 2;
3468                 sectordir = getSectorDir(p2d, 2);
3469         }
3470         
3471         /*
3472                 Make sure sector is loaded
3473         */
3474         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3475         if(sector == NULL)
3476         {
3477                 try{
3478                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3479                 }
3480                 catch(InvalidFilenameException &e)
3481                 {
3482                         return false;
3483                 }
3484                 catch(FileNotGoodException &e)
3485                 {
3486                         return false;
3487                 }
3488                 catch(std::exception &e)
3489                 {
3490                         return false;
3491                 }
3492         }
3493         
3494         /*
3495                 Make sure file exists
3496         */
3497
3498         std::string blockfilename = getBlockFilename(blockpos);
3499         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3500                 return NULL;
3501
3502         /*
3503                 Load block and save it to the database
3504         */
3505         loadBlock(sectordir, blockfilename, sector, true);
3506         return getBlockNoCreateNoEx(blockpos);
3507 }
3508
3509 void ServerMap::PrintInfo(std::ostream &out)
3510 {
3511         out<<"ServerMap: ";
3512 }
3513
3514 #ifndef SERVER
3515
3516 /*
3517         ClientMap
3518 */
3519
3520 ClientMap::ClientMap(
3521                 Client *client,
3522                 MapDrawControl &control,
3523                 scene::ISceneNode* parent,
3524                 scene::ISceneManager* mgr,
3525                 s32 id
3526 ):
3527         Map(dout_client),
3528         scene::ISceneNode(parent, mgr, id),
3529         m_client(client),
3530         m_control(control),
3531         m_camera_position(0,0,0),
3532         m_camera_direction(0,0,1),
3533         m_camera_fov(PI)
3534 {
3535         m_camera_mutex.Init();
3536         assert(m_camera_mutex.IsInitialized());
3537         
3538         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3539                         BS*1000000,BS*1000000,BS*1000000);
3540 }
3541
3542 ClientMap::~ClientMap()
3543 {
3544         /*JMutexAutoLock lock(mesh_mutex);
3545         
3546         if(mesh != NULL)
3547         {
3548                 mesh->drop();
3549                 mesh = NULL;
3550         }*/
3551 }
3552
3553 MapSector * ClientMap::emergeSector(v2s16 p2d)
3554 {
3555         DSTACK(__FUNCTION_NAME);
3556         // Check that it doesn't exist already
3557         try{
3558                 return getSectorNoGenerate(p2d);
3559         }
3560         catch(InvalidPositionException &e)
3561         {
3562         }
3563         
3564         // Create a sector
3565         ClientMapSector *sector = new ClientMapSector(this, p2d);
3566         
3567         {
3568                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3569                 m_sectors.insert(p2d, sector);
3570         }
3571         
3572         return sector;
3573 }
3574
3575 #if 0
3576 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3577 {
3578         DSTACK(__FUNCTION_NAME);
3579         ClientMapSector *sector = NULL;
3580
3581         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3582         
3583         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3584
3585         if(n != NULL)
3586         {
3587                 sector = (ClientMapSector*)n->getValue();
3588                 assert(sector->getId() == MAPSECTOR_CLIENT);
3589         }
3590         else
3591         {
3592                 sector = new ClientMapSector(this, p2d);
3593                 {
3594                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3595                         m_sectors.insert(p2d, sector);
3596                 }
3597         }
3598
3599         sector->deSerialize(is);
3600 }
3601 #endif
3602
3603 void ClientMap::OnRegisterSceneNode()
3604 {
3605         if(IsVisible)
3606         {
3607                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3608                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3609         }
3610
3611         ISceneNode::OnRegisterSceneNode();
3612 }
3613
3614 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3615 {
3616         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3617         DSTACK(__FUNCTION_NAME);
3618
3619         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3620         
3621         /*
3622                 This is called two times per frame, reset on the non-transparent one
3623         */
3624         if(pass == scene::ESNRP_SOLID)
3625         {
3626                 m_last_drawn_sectors.clear();
3627         }
3628
3629         /*
3630                 Get time for measuring timeout.
3631                 
3632                 Measuring time is very useful for long delays when the
3633                 machine is swapping a lot.
3634         */
3635         int time1 = time(0);
3636
3637         //u32 daynight_ratio = m_client->getDayNightRatio();
3638
3639         m_camera_mutex.Lock();
3640         v3f camera_position = m_camera_position;
3641         v3f camera_direction = m_camera_direction;
3642         f32 camera_fov = m_camera_fov;
3643         m_camera_mutex.Unlock();
3644
3645         /*
3646                 Get all blocks and draw all visible ones
3647         */
3648
3649         v3s16 cam_pos_nodes(
3650                         camera_position.X / BS,
3651                         camera_position.Y / BS,
3652                         camera_position.Z / BS);
3653
3654         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3655
3656         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3657         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3658
3659         // Take a fair amount as we will be dropping more out later
3660         v3s16 p_blocks_min(
3661                         p_nodes_min.X / MAP_BLOCKSIZE - 2,
3662                         p_nodes_min.Y / MAP_BLOCKSIZE - 2,
3663                         p_nodes_min.Z / MAP_BLOCKSIZE - 2);
3664         v3s16 p_blocks_max(
3665                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3666                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3667                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3668         
3669         u32 vertex_count = 0;
3670         u32 meshbuffer_count = 0;
3671         
3672         // For limiting number of mesh updates per frame
3673         u32 mesh_update_count = 0;
3674         
3675         u32 blocks_would_have_drawn = 0;
3676         u32 blocks_drawn = 0;
3677
3678         int timecheck_counter = 0;
3679         core::map<v2s16, MapSector*>::Iterator si;
3680         si = m_sectors.getIterator();
3681         for(; si.atEnd() == false; si++)
3682         {
3683                 {
3684                         timecheck_counter++;
3685                         if(timecheck_counter > 50)
3686                         {
3687                                 timecheck_counter = 0;
3688                                 int time2 = time(0);
3689                                 if(time2 > time1 + 4)
3690                                 {
3691                                         infostream<<"ClientMap::renderMap(): "
3692                                                 "Rendering takes ages, returning."
3693                                                 <<std::endl;
3694                                         return;
3695                                 }
3696                         }
3697                 }
3698
3699                 MapSector *sector = si.getNode()->getValue();
3700                 v2s16 sp = sector->getPos();
3701                 
3702                 if(m_control.range_all == false)
3703                 {
3704                         if(sp.X < p_blocks_min.X
3705                         || sp.X > p_blocks_max.X
3706                         || sp.Y < p_blocks_min.Z
3707                         || sp.Y > p_blocks_max.Z)
3708                                 continue;
3709                 }
3710
3711                 core::list< MapBlock * > sectorblocks;
3712                 sector->getBlocks(sectorblocks);
3713                 
3714                 /*
3715                         Draw blocks
3716                 */
3717                 
3718                 u32 sector_blocks_drawn = 0;
3719
3720                 core::list< MapBlock * >::Iterator i;
3721                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3722                 {
3723                         MapBlock *block = *i;
3724
3725                         /*
3726                                 Compare block position to camera position, skip
3727                                 if not seen on display
3728                         */
3729                         
3730                         float range = 100000 * BS;
3731                         if(m_control.range_all == false)
3732                                 range = m_control.wanted_range * BS;
3733                         
3734                         float d = 0.0;
3735                         if(isBlockInSight(block->getPos(), camera_position,
3736                                         camera_direction, camera_fov,
3737                                         range, &d) == false)
3738                         {
3739                                 continue;
3740                         }
3741
3742                         // Okay, this block will be drawn. Reset usage timer.
3743                         block->resetUsageTimer();
3744                         
3745                         // This is ugly (spherical distance limit?)
3746                         /*if(m_control.range_all == false &&
3747                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3748                                 continue;*/
3749
3750 #if 1
3751                         /*
3752                                 Update expired mesh (used for day/night change)
3753
3754                                 It doesn't work exactly like it should now with the
3755                                 tasked mesh update but whatever.
3756                         */
3757
3758                         bool mesh_expired = false;
3759                         
3760                         {
3761                                 JMutexAutoLock lock(block->mesh_mutex);
3762
3763                                 mesh_expired = block->getMeshExpired();
3764
3765                                 // Mesh has not been expired and there is no mesh:
3766                                 // block has no content
3767                                 if(block->mesh == NULL && mesh_expired == false)
3768                                         continue;
3769                         }
3770
3771                         f32 faraway = BS*50;
3772                         //f32 faraway = m_control.wanted_range * BS;
3773                         
3774                         /*
3775                                 This has to be done with the mesh_mutex unlocked
3776                         */
3777                         // Pretty random but this should work somewhat nicely
3778                         if(mesh_expired && (
3779                                         (mesh_update_count < 3
3780                                                 && (d < faraway || mesh_update_count < 2)
3781                                         )
3782                                         || 
3783                                         (m_control.range_all && mesh_update_count < 20)
3784                                 )
3785                         )
3786                         /*if(mesh_expired && mesh_update_count < 6
3787                                         && (d < faraway || mesh_update_count < 3))*/
3788                         {
3789                                 mesh_update_count++;
3790
3791                                 // Mesh has been expired: generate new mesh
3792                                 //block->updateMesh(daynight_ratio);
3793                                 m_client->addUpdateMeshTask(block->getPos());
3794
3795                                 mesh_expired = false;
3796                         }
3797                         
3798 #endif
3799                         /*
3800                                 Draw the faces of the block
3801                         */
3802                         {
3803                                 JMutexAutoLock lock(block->mesh_mutex);
3804
3805                                 scene::SMesh *mesh = block->mesh;
3806
3807                                 if(mesh == NULL)
3808                                         continue;
3809                                 
3810                                 blocks_would_have_drawn++;
3811                                 if(blocks_drawn >= m_control.wanted_max_blocks
3812                                                 && m_control.range_all == false
3813                                                 && d > m_control.wanted_min_range * BS)
3814                                         continue;
3815
3816                                 blocks_drawn++;
3817                                 sector_blocks_drawn++;
3818
3819                                 u32 c = mesh->getMeshBufferCount();
3820                                 meshbuffer_count += c;
3821
3822                                 for(u32 i=0; i<c; i++)
3823                                 {
3824                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3825                                         const video::SMaterial& material = buf->getMaterial();
3826                                         video::IMaterialRenderer* rnd =
3827                                                         driver->getMaterialRenderer(material.MaterialType);
3828                                         bool transparent = (rnd && rnd->isTransparent());
3829                                         // Render transparent on transparent pass and likewise.
3830                                         if(transparent == is_transparent_pass)
3831                                         {
3832                                                 /*
3833                                                         This *shouldn't* hurt too much because Irrlicht
3834                                                         doesn't change opengl textures if the old
3835                                                         material is set again.
3836                                                 */
3837                                                 driver->setMaterial(buf->getMaterial());
3838                                                 driver->drawMeshBuffer(buf);
3839                                                 vertex_count += buf->getVertexCount();
3840                                         }
3841                                 }
3842                         }
3843                 } // foreach sectorblocks
3844
3845                 if(sector_blocks_drawn != 0)
3846                 {
3847                         m_last_drawn_sectors[sp] = true;
3848                 }
3849         }
3850         
3851         if(pass == scene::ESNRP_SOLID){
3852                 g_profiler->avg("CM: blocks drawn on solid pass", blocks_drawn);
3853                 g_profiler->avg("CM: vertices drawn on solid pass", vertex_count);
3854                 if(blocks_drawn != 0)
3855                         g_profiler->avg("CM: solid meshbuffers per block",
3856                                         (float)meshbuffer_count / (float)blocks_drawn);
3857         } else {
3858                 g_profiler->avg("CM: blocks drawn on transparent pass", blocks_drawn);
3859                 g_profiler->avg("CM: vertices drawn on transparent pass", vertex_count);
3860         }
3861         
3862         m_control.blocks_drawn = blocks_drawn;
3863         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3864
3865         /*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3866                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3867 }
3868
3869 void ClientMap::renderPostFx()
3870 {
3871         // Sadly ISceneManager has no "post effects" render pass, in that case we
3872         // could just register for that and handle it in renderMap().
3873
3874         m_camera_mutex.Lock();
3875         v3f camera_position = m_camera_position;
3876         m_camera_mutex.Unlock();
3877
3878         MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
3879
3880         // - If the player is in a solid node, make everything black.
3881         // - If the player is in liquid, draw a semi-transparent overlay.
3882         ContentFeatures& features = content_features(n);
3883         video::SColor post_effect_color = features.post_effect_color;
3884         if(features.solidness == 2 && g_settings->getBool("free_move") == false)
3885         {
3886                 post_effect_color = video::SColor(255, 0, 0, 0);
3887         }
3888         if (post_effect_color.getAlpha() != 0)
3889         {
3890                 // Draw a full-screen rectangle
3891                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
3892                 v2u32 ss = driver->getScreenSize();
3893                 core::rect<s32> rect(0,0, ss.X, ss.Y);
3894                 driver->draw2DRectangle(post_effect_color, rect);
3895         }
3896 }
3897
3898 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
3899                 core::map<v3s16, MapBlock*> *affected_blocks)
3900 {
3901         bool changed = false;
3902         /*
3903                 Add it to all blocks touching it
3904         */
3905         v3s16 dirs[7] = {
3906                 v3s16(0,0,0), // this
3907                 v3s16(0,0,1), // back
3908                 v3s16(0,1,0), // top
3909                 v3s16(1,0,0), // right
3910                 v3s16(0,0,-1), // front
3911                 v3s16(0,-1,0), // bottom
3912                 v3s16(-1,0,0), // left
3913         };
3914         for(u16 i=0; i<7; i++)
3915         {
3916                 v3s16 p2 = p + dirs[i];
3917                 // Block position of neighbor (or requested) node
3918                 v3s16 blockpos = getNodeBlockPos(p2);
3919                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3920                 if(blockref == NULL)
3921                         continue;
3922                 // Relative position of requested node
3923                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3924                 if(blockref->setTempMod(relpos, mod))
3925                 {
3926                         changed = true;
3927                 }
3928         }
3929         if(changed && affected_blocks!=NULL)
3930         {
3931                 for(u16 i=0; i<7; i++)
3932                 {
3933                         v3s16 p2 = p + dirs[i];
3934                         // Block position of neighbor (or requested) node
3935                         v3s16 blockpos = getNodeBlockPos(p2);
3936                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3937                         if(blockref == NULL)
3938                                 continue;
3939                         affected_blocks->insert(blockpos, blockref);
3940                 }
3941         }
3942         return changed;
3943 }
3944
3945 bool ClientMap::clearTempMod(v3s16 p,
3946                 core::map<v3s16, MapBlock*> *affected_blocks)
3947 {
3948         bool changed = false;
3949         v3s16 dirs[7] = {
3950                 v3s16(0,0,0), // this
3951                 v3s16(0,0,1), // back
3952                 v3s16(0,1,0), // top
3953                 v3s16(1,0,0), // right
3954                 v3s16(0,0,-1), // front
3955                 v3s16(0,-1,0), // bottom
3956                 v3s16(-1,0,0), // left
3957         };
3958         for(u16 i=0; i<7; i++)
3959         {
3960                 v3s16 p2 = p + dirs[i];
3961                 // Block position of neighbor (or requested) node
3962                 v3s16 blockpos = getNodeBlockPos(p2);
3963                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3964                 if(blockref == NULL)
3965                         continue;
3966                 // Relative position of requested node
3967                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3968                 if(blockref->clearTempMod(relpos))
3969                 {
3970                         changed = true;
3971                 }
3972         }
3973         if(changed && affected_blocks!=NULL)
3974         {
3975                 for(u16 i=0; i<7; i++)
3976                 {
3977                         v3s16 p2 = p + dirs[i];
3978                         // Block position of neighbor (or requested) node
3979                         v3s16 blockpos = getNodeBlockPos(p2);
3980                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3981                         if(blockref == NULL)
3982                                 continue;
3983                         affected_blocks->insert(blockpos, blockref);
3984                 }
3985         }
3986         return changed;
3987 }
3988
3989 void ClientMap::expireMeshes(bool only_daynight_diffed)
3990 {
3991         TimeTaker timer("expireMeshes()");
3992
3993         core::map<v2s16, MapSector*>::Iterator si;
3994         si = m_sectors.getIterator();
3995         for(; si.atEnd() == false; si++)
3996         {
3997                 MapSector *sector = si.getNode()->getValue();
3998
3999                 core::list< MapBlock * > sectorblocks;
4000                 sector->getBlocks(sectorblocks);
4001                 
4002                 core::list< MapBlock * >::Iterator i;
4003                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
4004                 {
4005                         MapBlock *block = *i;
4006
4007                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
4008                         {
4009                                 continue;
4010                         }
4011                         
4012                         {
4013                                 JMutexAutoLock lock(block->mesh_mutex);
4014                                 if(block->mesh != NULL)
4015                                 {
4016                                         /*block->mesh->drop();
4017                                         block->mesh = NULL;*/
4018                                         block->setMeshExpired(true);
4019                                 }
4020                         }
4021                 }
4022         }
4023 }
4024
4025 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
4026 {
4027         assert(mapType() == MAPTYPE_CLIENT);
4028
4029         try{
4030                 v3s16 p = blockpos + v3s16(0,0,0);
4031                 MapBlock *b = getBlockNoCreate(p);
4032                 b->updateMesh(daynight_ratio);
4033                 //b->setMeshExpired(true);
4034         }
4035         catch(InvalidPositionException &e){}
4036         // Leading edge
4037         try{
4038                 v3s16 p = blockpos + v3s16(-1,0,0);
4039                 MapBlock *b = getBlockNoCreate(p);
4040                 b->updateMesh(daynight_ratio);
4041                 //b->setMeshExpired(true);
4042         }
4043         catch(InvalidPositionException &e){}
4044         try{
4045                 v3s16 p = blockpos + v3s16(0,-1,0);
4046                 MapBlock *b = getBlockNoCreate(p);
4047                 b->updateMesh(daynight_ratio);
4048                 //b->setMeshExpired(true);
4049         }
4050         catch(InvalidPositionException &e){}
4051         try{
4052                 v3s16 p = blockpos + v3s16(0,0,-1);
4053                 MapBlock *b = getBlockNoCreate(p);
4054                 b->updateMesh(daynight_ratio);
4055                 //b->setMeshExpired(true);
4056         }
4057         catch(InvalidPositionException &e){}
4058 }
4059
4060 #if 0
4061 /*
4062         Update mesh of block in which the node is, and if the node is at the
4063         leading edge, update the appropriate leading blocks too.
4064 */
4065 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
4066 {
4067         v3s16 dirs[4] = {
4068                 v3s16(0,0,0),
4069                 v3s16(-1,0,0),
4070                 v3s16(0,-1,0),
4071                 v3s16(0,0,-1),
4072         };
4073         v3s16 blockposes[4];
4074         for(u32 i=0; i<4; i++)
4075         {
4076                 v3s16 np = nodepos + dirs[i];
4077                 blockposes[i] = getNodeBlockPos(np);
4078                 // Don't update mesh of block if it has been done already
4079                 bool already_updated = false;
4080                 for(u32 j=0; j<i; j++)
4081                 {
4082                         if(blockposes[j] == blockposes[i])
4083                         {
4084                                 already_updated = true;
4085                                 break;
4086                         }
4087                 }
4088                 if(already_updated)
4089                         continue;
4090                 // Update mesh
4091                 MapBlock *b = getBlockNoCreate(blockposes[i]);
4092                 b->updateMesh(daynight_ratio);
4093         }
4094 }
4095 #endif
4096
4097 void ClientMap::PrintInfo(std::ostream &out)
4098 {
4099         out<<"ClientMap: ";
4100 }
4101
4102 #endif // !SERVER
4103
4104 /*
4105         MapVoxelManipulator
4106 */
4107
4108 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4109 {
4110         m_map = map;
4111 }
4112
4113 MapVoxelManipulator::~MapVoxelManipulator()
4114 {
4115         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4116                         <<std::endl;*/
4117 }
4118
4119 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4120 {
4121         TimeTaker timer1("emerge", &emerge_time);
4122
4123         // Units of these are MapBlocks
4124         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4125         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4126
4127         VoxelArea block_area_nodes
4128                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4129
4130         addArea(block_area_nodes);
4131
4132         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4133         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4134         for(s32 x=p_min.X; x<=p_max.X; x++)
4135         {
4136                 v3s16 p(x,y,z);
4137                 core::map<v3s16, bool>::Node *n;
4138                 n = m_loaded_blocks.find(p);
4139                 if(n != NULL)
4140                         continue;
4141                 
4142                 bool block_data_inexistent = false;
4143                 try
4144                 {
4145                         TimeTaker timer1("emerge load", &emerge_load_time);
4146
4147                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4148                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4149                                         <<" wanted area: ";
4150                         a.print(infostream);
4151                         infostream<<std::endl;*/
4152                         
4153                         MapBlock *block = m_map->getBlockNoCreate(p);
4154                         if(block->isDummy())
4155                                 block_data_inexistent = true;
4156                         else
4157                                 block->copyTo(*this);
4158                 }
4159                 catch(InvalidPositionException &e)
4160                 {
4161                         block_data_inexistent = true;
4162                 }
4163
4164                 if(block_data_inexistent)
4165                 {
4166                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4167                         // Fill with VOXELFLAG_INEXISTENT
4168                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4169                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4170                         {
4171                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4172                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4173                         }
4174                 }
4175
4176                 m_loaded_blocks.insert(p, !block_data_inexistent);
4177         }
4178
4179         //infostream<<"emerge done"<<std::endl;
4180 }
4181
4182 /*
4183         SUGG: Add an option to only update eg. water and air nodes.
4184               This will make it interfere less with important stuff if
4185                   run on background.
4186 */
4187 void MapVoxelManipulator::blitBack
4188                 (core::map<v3s16, MapBlock*> & modified_blocks)
4189 {
4190         if(m_area.getExtent() == v3s16(0,0,0))
4191                 return;
4192         
4193         //TimeTaker timer1("blitBack");
4194
4195         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4196                         <<m_loaded_blocks.size()<<std::endl;*/
4197         
4198         /*
4199                 Initialize block cache
4200         */
4201         v3s16 blockpos_last;
4202         MapBlock *block = NULL;
4203         bool block_checked_in_modified = false;
4204
4205         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4206         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4207         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4208         {
4209                 v3s16 p(x,y,z);
4210
4211                 u8 f = m_flags[m_area.index(p)];
4212                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4213                         continue;
4214
4215                 MapNode &n = m_data[m_area.index(p)];
4216                         
4217                 v3s16 blockpos = getNodeBlockPos(p);
4218                 
4219                 try
4220                 {
4221                         // Get block
4222                         if(block == NULL || blockpos != blockpos_last){
4223                                 block = m_map->getBlockNoCreate(blockpos);
4224                                 blockpos_last = blockpos;
4225                                 block_checked_in_modified = false;
4226                         }
4227                         
4228                         // Calculate relative position in block
4229                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4230
4231                         // Don't continue if nothing has changed here
4232                         if(block->getNode(relpos) == n)
4233                                 continue;
4234
4235                         //m_map->setNode(m_area.MinEdge + p, n);
4236                         block->setNode(relpos, n);
4237                         
4238                         /*
4239                                 Make sure block is in modified_blocks
4240                         */
4241                         if(block_checked_in_modified == false)
4242                         {
4243                                 modified_blocks[blockpos] = block;
4244                                 block_checked_in_modified = true;
4245                         }
4246                 }
4247                 catch(InvalidPositionException &e)
4248                 {
4249                 }
4250         }
4251 }
4252
4253 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4254                 MapVoxelManipulator(map),
4255                 m_create_area(false)
4256 {
4257 }
4258
4259 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4260 {
4261 }
4262
4263 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4264 {
4265         // Just create the area so that it can be pointed to
4266         VoxelManipulator::emerge(a, caller_id);
4267 }
4268
4269 void ManualMapVoxelManipulator::initialEmerge(
4270                 v3s16 blockpos_min, v3s16 blockpos_max)
4271 {
4272         TimeTaker timer1("initialEmerge", &emerge_time);
4273
4274         // Units of these are MapBlocks
4275         v3s16 p_min = blockpos_min;
4276         v3s16 p_max = blockpos_max;
4277
4278         VoxelArea block_area_nodes
4279                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4280         
4281         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4282         if(size_MB >= 1)
4283         {
4284                 infostream<<"initialEmerge: area: ";
4285                 block_area_nodes.print(infostream);
4286                 infostream<<" ("<<size_MB<<"MB)";
4287                 infostream<<std::endl;
4288         }
4289
4290         addArea(block_area_nodes);
4291
4292         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4293         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4294         for(s32 x=p_min.X; x<=p_max.X; x++)
4295         {
4296                 v3s16 p(x,y,z);
4297                 core::map<v3s16, bool>::Node *n;
4298                 n = m_loaded_blocks.find(p);
4299                 if(n != NULL)
4300                         continue;
4301                 
4302                 bool block_data_inexistent = false;
4303                 try
4304                 {
4305                         TimeTaker timer1("emerge load", &emerge_load_time);
4306
4307                         MapBlock *block = m_map->getBlockNoCreate(p);
4308                         if(block->isDummy())
4309                                 block_data_inexistent = true;
4310                         else
4311                                 block->copyTo(*this);
4312                 }
4313                 catch(InvalidPositionException &e)
4314                 {
4315                         block_data_inexistent = true;
4316                 }
4317
4318                 if(block_data_inexistent)
4319                 {
4320                         /*
4321                                 Mark area inexistent
4322                         */
4323                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4324                         // Fill with VOXELFLAG_INEXISTENT
4325                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4326                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4327                         {
4328                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4329                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4330                         }
4331                 }
4332
4333                 m_loaded_blocks.insert(p, !block_data_inexistent);
4334         }
4335 }
4336
4337 void ManualMapVoxelManipulator::blitBackAll(
4338                 core::map<v3s16, MapBlock*> * modified_blocks)
4339 {
4340         if(m_area.getExtent() == v3s16(0,0,0))
4341                 return;
4342         
4343         /*
4344                 Copy data of all blocks
4345         */
4346         for(core::map<v3s16, bool>::Iterator
4347                         i = m_loaded_blocks.getIterator();
4348                         i.atEnd() == false; i++)
4349         {
4350                 v3s16 p = i.getNode()->getKey();
4351                 bool existed = i.getNode()->getValue();
4352                 if(existed == false)
4353                 {
4354                         // The Great Bug was found using this
4355                         /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
4356                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4357                                         <<std::endl;*/
4358                         continue;
4359                 }
4360                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4361                 if(block == NULL)
4362                 {
4363                         infostream<<"WARNING: "<<__FUNCTION_NAME
4364                                         <<": got NULL block "
4365                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4366                                         <<std::endl;
4367                         continue;
4368                 }
4369
4370                 block->copyFrom(*this);
4371
4372                 if(modified_blocks)
4373                         modified_blocks->insert(p, block);
4374         }
4375 }
4376
4377 //END