Catch SendFailedException when replying back in Connection::Receive()
[oweals/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 #if 0
2627         /*
2628                 Do not generate over-limit
2629         */
2630         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2631         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2632         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2633         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2634         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2635         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2636                 throw InvalidPositionException("emergeBlock(): pos. over limit");
2637         
2638         v2s16 p2d(p.X, p.Z);
2639         s16 block_y = p.Y;
2640         /*
2641                 This will create or load a sector if not found in memory.
2642                 If block exists on disk, it will be loaded.
2643         */
2644         ServerMapSector *sector;
2645         try{
2646                 sector = createSector(p2d);
2647                 //sector = emergeSector(p2d, changed_blocks);
2648         }
2649         catch(InvalidPositionException &e)
2650         {
2651                 infostream<<"emergeBlock: createSector() failed: "
2652                                 <<e.what()<<std::endl;
2653                 infostream<<"Path to failed sector: "<<getSectorDir(p2d)
2654                                 <<std::endl
2655                                 <<"You could try to delete it."<<std::endl;
2656                 throw e;
2657         }
2658         catch(VersionMismatchException &e)
2659         {
2660                 infostream<<"emergeBlock: createSector() failed: "
2661                                 <<e.what()<<std::endl;
2662                 infostream<<"Path to failed sector: "<<getSectorDir(p2d)
2663                                 <<std::endl
2664                                 <<"You could try to delete it."<<std::endl;
2665                 throw e;
2666         }
2667
2668         /*
2669                 Try to get a block from the sector
2670         */
2671
2672         bool does_not_exist = false;
2673         bool lighting_expired = false;
2674         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2675         
2676         // If not found, try loading from disk
2677         if(block == NULL)
2678         {
2679                 block = loadBlock(p);
2680         }
2681         
2682         // Handle result
2683         if(block == NULL)
2684         {
2685                 does_not_exist = true;
2686         }
2687         else if(block->isDummy() == true)
2688         {
2689                 does_not_exist = true;
2690         }
2691         else if(block->getLightingExpired())
2692         {
2693                 lighting_expired = true;
2694         }
2695         else
2696         {
2697                 // Valid block
2698                 //infostream<<"emergeBlock(): Returning already valid block"<<std::endl;
2699                 return block;
2700         }
2701         
2702         /*
2703                 If block was not found on disk and not going to generate a
2704                 new one, make sure there is a dummy block in place.
2705         */
2706         if(only_from_disk && (does_not_exist || lighting_expired))
2707         {
2708                 //infostream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
2709
2710                 if(block == NULL)
2711                 {
2712                         // Create dummy block
2713                         block = new MapBlock(this, p, true);
2714
2715                         // Add block to sector
2716                         sector->insertBlock(block);
2717                 }
2718                 // Done.
2719                 return block;
2720         }
2721
2722         //infostream<<"Not found on disk, generating."<<std::endl;
2723         // 0ms
2724         //TimeTaker("emergeBlock() generate");
2725
2726         //infostream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
2727
2728         /*
2729                 If the block doesn't exist, generate the block.
2730         */
2731         if(does_not_exist)
2732         {
2733                 block = generateBlock(p, block, sector, changed_blocks,
2734                                 lighting_invalidated_blocks); 
2735         }
2736
2737         if(lighting_expired)
2738         {
2739                 lighting_invalidated_blocks.insert(p, block);
2740         }
2741
2742 #if 0
2743         /*
2744                 Initially update sunlight
2745         */
2746         {
2747                 core::map<v3s16, bool> light_sources;
2748                 bool black_air_left = false;
2749                 bool bottom_invalid =
2750                                 block->propagateSunlight(light_sources, true,
2751                                 &black_air_left);
2752
2753                 // If sunlight didn't reach everywhere and part of block is
2754                 // above ground, lighting has to be properly updated
2755                 //if(black_air_left && some_part_underground)
2756                 if(black_air_left)
2757                 {
2758                         lighting_invalidated_blocks[block->getPos()] = block;
2759                 }
2760
2761                 if(bottom_invalid)
2762                 {
2763                         lighting_invalidated_blocks[block->getPos()] = block;
2764                 }
2765         }
2766 #endif
2767         
2768         return block;
2769 }
2770 #endif
2771
2772 s16 ServerMap::findGroundLevel(v2s16 p2d)
2773 {
2774 #if 0
2775         /*
2776                 Uh, just do something random...
2777         */
2778         // Find existing map from top to down
2779         s16 max=63;
2780         s16 min=-64;
2781         v3s16 p(p2d.X, max, p2d.Y);
2782         for(; p.Y>min; p.Y--)
2783         {
2784                 MapNode n = getNodeNoEx(p);
2785                 if(n.getContent() != CONTENT_IGNORE)
2786                         break;
2787         }
2788         if(p.Y == min)
2789                 goto plan_b;
2790         // If this node is not air, go to plan b
2791         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2792                 goto plan_b;
2793         // Search existing walkable and return it
2794         for(; p.Y>min; p.Y--)
2795         {
2796                 MapNode n = getNodeNoEx(p);
2797                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2798                         return p.Y;
2799         }
2800
2801         // Move to plan b
2802 plan_b:
2803 #endif
2804
2805         /*
2806                 Determine from map generator noise functions
2807         */
2808         
2809         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2810         return level;
2811
2812         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2813         //return (s16)level;
2814 }
2815
2816 void ServerMap::createDatabase() {
2817         int e;
2818         assert(m_database);
2819         e = sqlite3_exec(m_database,
2820                 "CREATE TABLE IF NOT EXISTS `blocks` ("
2821                         "`pos` INT NOT NULL PRIMARY KEY,"
2822                         "`data` BLOB"
2823                 ");"
2824         , NULL, NULL, NULL);
2825         if(e == SQLITE_ABORT)
2826                 throw FileNotGoodException("Could not create database structure");
2827         else
2828                 infostream<<"Server: Database structure was created";
2829 }
2830
2831 void ServerMap::verifyDatabase() {
2832         if(m_database)
2833                 return;
2834         
2835         {
2836                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
2837                 bool needs_create = false;
2838                 int d;
2839                 
2840                 /*
2841                         Open the database connection
2842                 */
2843         
2844                 createDirs(m_savedir);
2845         
2846                 if(!fs::PathExists(dbp))
2847                         needs_create = true;
2848         
2849                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
2850                 if(d != SQLITE_OK) {
2851                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
2852                         throw FileNotGoodException("Cannot open database file");
2853                 }
2854                 
2855                 if(needs_create)
2856                         createDatabase();
2857         
2858                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
2859                 if(d != SQLITE_OK) {
2860                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2861                         throw FileNotGoodException("Cannot prepare read statement");
2862                 }
2863                 
2864                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
2865                 if(d != SQLITE_OK) {
2866                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2867                         throw FileNotGoodException("Cannot prepare write statement");
2868                 }
2869                 
2870                 infostream<<"Server: Database opened"<<std::endl;
2871         }
2872 }
2873
2874 bool ServerMap::loadFromFolders() {
2875         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2876                 return true;
2877         return false;
2878 }
2879
2880 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
2881         return (sqlite3_int64)pos.Z*16777216 +
2882                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
2883 }
2884
2885 void ServerMap::createDirs(std::string path)
2886 {
2887         if(fs::CreateAllDirs(path) == false)
2888         {
2889                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2890                                 <<"\""<<path<<"\""<<std::endl;
2891                 throw BaseException("ServerMap failed to create directory");
2892         }
2893 }
2894
2895 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2896 {
2897         char cc[9];
2898         switch(layout)
2899         {
2900                 case 1:
2901                         snprintf(cc, 9, "%.4x%.4x",
2902                                 (unsigned int)pos.X&0xffff,
2903                                 (unsigned int)pos.Y&0xffff);
2904
2905                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2906                 case 2:
2907                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2908                                 (unsigned int)pos.X&0xfff,
2909                                 (unsigned int)pos.Y&0xfff);
2910
2911                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2912                 default:
2913                         assert(false);
2914         }
2915 }
2916
2917 v2s16 ServerMap::getSectorPos(std::string dirname)
2918 {
2919         unsigned int x, y;
2920         int r;
2921         size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
2922         assert(spos != std::string::npos);
2923         if(dirname.size() - spos == 8)
2924         {
2925                 // Old layout
2926                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2927         }
2928         else if(dirname.size() - spos == 3)
2929         {
2930                 // New layout
2931                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2932                 // Sign-extend the 12 bit values up to 16 bits...
2933                 if(x&0x800) x|=0xF000;
2934                 if(y&0x800) y|=0xF000;
2935         }
2936         else
2937         {
2938                 assert(false);
2939         }
2940         assert(r == 2);
2941         v2s16 pos((s16)x, (s16)y);
2942         return pos;
2943 }
2944
2945 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2946 {
2947         v2s16 p2d = getSectorPos(sectordir);
2948
2949         if(blockfile.size() != 4){
2950                 throw InvalidFilenameException("Invalid block filename");
2951         }
2952         unsigned int y;
2953         int r = sscanf(blockfile.c_str(), "%4x", &y);
2954         if(r != 1)
2955                 throw InvalidFilenameException("Invalid block filename");
2956         return v3s16(p2d.X, y, p2d.Y);
2957 }
2958
2959 std::string ServerMap::getBlockFilename(v3s16 p)
2960 {
2961         char cc[5];
2962         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2963         return cc;
2964 }
2965
2966 void ServerMap::save(bool only_changed)
2967 {
2968         DSTACK(__FUNCTION_NAME);
2969         if(m_map_saving_enabled == false)
2970         {
2971                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2972                 return;
2973         }
2974         
2975         if(only_changed == false)
2976                 infostream<<"ServerMap: Saving whole map, this can take time."
2977                                 <<std::endl;
2978         
2979         if(only_changed == false || m_map_metadata_changed)
2980         {
2981                 saveMapMeta();
2982         }
2983
2984         u32 sector_meta_count = 0;
2985         u32 block_count = 0;
2986         u32 block_count_all = 0; // Number of blocks in memory
2987         
2988         beginSave();
2989         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2990         for(; i.atEnd() == false; i++)
2991         {
2992                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2993                 assert(sector->getId() == MAPSECTOR_SERVER);
2994         
2995                 if(sector->differs_from_disk || only_changed == false)
2996                 {
2997                         saveSectorMeta(sector);
2998                         sector_meta_count++;
2999                 }
3000                 core::list<MapBlock*> blocks;
3001                 sector->getBlocks(blocks);
3002                 core::list<MapBlock*>::Iterator j;
3003                 
3004                 //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL);
3005                 for(j=blocks.begin(); j!=blocks.end(); j++)
3006                 {
3007                         MapBlock *block = *j;
3008                         
3009                         block_count_all++;
3010
3011                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
3012                                         || only_changed == false)
3013                         {
3014                                 saveBlock(block);
3015                                 block_count++;
3016
3017                                 /*infostream<<"ServerMap: Written block ("
3018                                                 <<block->getPos().X<<","
3019                                                 <<block->getPos().Y<<","
3020                                                 <<block->getPos().Z<<")"
3021                                                 <<std::endl;*/
3022                         }
3023                 //sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL);
3024                 }
3025         }
3026         endSave();
3027
3028         /*
3029                 Only print if something happened or saved whole map
3030         */
3031         if(only_changed == false || sector_meta_count != 0
3032                         || block_count != 0)
3033         {
3034                 infostream<<"ServerMap: Written: "
3035                                 <<sector_meta_count<<" sector metadata files, "
3036                                 <<block_count<<" block files"
3037                                 <<", "<<block_count_all<<" blocks in memory."
3038                                 <<std::endl;
3039         }
3040 }
3041
3042 void ServerMap::saveMapMeta()
3043 {
3044         DSTACK(__FUNCTION_NAME);
3045         
3046         infostream<<"ServerMap::saveMapMeta(): "
3047                         <<"seed="<<m_seed
3048                         <<std::endl;
3049
3050         createDirs(m_savedir);
3051         
3052         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3053         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
3054         if(os.good() == false)
3055         {
3056                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3057                                 <<"could not open"<<fullpath<<std::endl;
3058                 throw FileNotGoodException("Cannot open chunk metadata");
3059         }
3060         
3061         Settings params;
3062         params.setU64("seed", m_seed);
3063
3064         params.writeLines(os);
3065
3066         os<<"[end_of_params]\n";
3067         
3068         m_map_metadata_changed = false;
3069 }
3070
3071 void ServerMap::loadMapMeta()
3072 {
3073         DSTACK(__FUNCTION_NAME);
3074         
3075         infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3076                         <<std::endl;
3077
3078         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3079         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3080         if(is.good() == false)
3081         {
3082                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3083                                 <<"could not open"<<fullpath<<std::endl;
3084                 throw FileNotGoodException("Cannot open map metadata");
3085         }
3086
3087         Settings params;
3088
3089         for(;;)
3090         {
3091                 if(is.eof())
3092                         throw SerializationError
3093                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3094                 std::string line;
3095                 std::getline(is, line);
3096                 std::string trimmedline = trim(line);
3097                 if(trimmedline == "[end_of_params]")
3098                         break;
3099                 params.parseConfigLine(line);
3100         }
3101
3102         m_seed = params.getU64("seed");
3103
3104         infostream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3105 }
3106
3107 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3108 {
3109         DSTACK(__FUNCTION_NAME);
3110         // Format used for writing
3111         u8 version = SER_FMT_VER_HIGHEST;
3112         // Get destination
3113         v2s16 pos = sector->getPos();
3114         std::string dir = getSectorDir(pos);
3115         createDirs(dir);
3116         
3117         std::string fullpath = dir + DIR_DELIM + "meta";
3118         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3119         if(o.good() == false)
3120                 throw FileNotGoodException("Cannot open sector metafile");
3121
3122         sector->serialize(o, version);
3123         
3124         sector->differs_from_disk = false;
3125 }
3126
3127 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3128 {
3129         DSTACK(__FUNCTION_NAME);
3130         // Get destination
3131         v2s16 p2d = getSectorPos(sectordir);
3132
3133         ServerMapSector *sector = NULL;
3134
3135         std::string fullpath = sectordir + DIR_DELIM + "meta";
3136         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3137         if(is.good() == false)
3138         {
3139                 // If the directory exists anyway, it probably is in some old
3140                 // format. Just go ahead and create the sector.
3141                 if(fs::PathExists(sectordir))
3142                 {
3143                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3144                                         <<fullpath<<" doesn't exist but directory does."
3145                                         <<" Continuing with a sector with no metadata."
3146                                         <<std::endl;*/
3147                         sector = new ServerMapSector(this, p2d);
3148                         m_sectors.insert(p2d, sector);
3149                 }
3150                 else
3151                 {
3152                         throw FileNotGoodException("Cannot open sector metafile");
3153                 }
3154         }
3155         else
3156         {
3157                 sector = ServerMapSector::deSerialize
3158                                 (is, this, p2d, m_sectors);
3159                 if(save_after_load)
3160                         saveSectorMeta(sector);
3161         }
3162         
3163         sector->differs_from_disk = false;
3164
3165         return sector;
3166 }
3167
3168 bool ServerMap::loadSectorMeta(v2s16 p2d)
3169 {
3170         DSTACK(__FUNCTION_NAME);
3171
3172         MapSector *sector = NULL;
3173
3174         // The directory layout we're going to load from.
3175         //  1 - original sectors/xxxxzzzz/
3176         //  2 - new sectors2/xxx/zzz/
3177         //  If we load from anything but the latest structure, we will
3178         //  immediately save to the new one, and remove the old.
3179         int loadlayout = 1;
3180         std::string sectordir1 = getSectorDir(p2d, 1);
3181         std::string sectordir;
3182         if(fs::PathExists(sectordir1))
3183         {
3184                 sectordir = sectordir1;
3185         }
3186         else
3187         {
3188                 loadlayout = 2;
3189                 sectordir = getSectorDir(p2d, 2);
3190         }
3191
3192         try{
3193                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3194         }
3195         catch(InvalidFilenameException &e)
3196         {
3197                 return false;
3198         }
3199         catch(FileNotGoodException &e)
3200         {
3201                 return false;
3202         }
3203         catch(std::exception &e)
3204         {
3205                 return false;
3206         }
3207         
3208         return true;
3209 }
3210
3211 #if 0
3212 bool ServerMap::loadSectorFull(v2s16 p2d)
3213 {
3214         DSTACK(__FUNCTION_NAME);
3215
3216         MapSector *sector = NULL;
3217
3218         // The directory layout we're going to load from.
3219         //  1 - original sectors/xxxxzzzz/
3220         //  2 - new sectors2/xxx/zzz/
3221         //  If we load from anything but the latest structure, we will
3222         //  immediately save to the new one, and remove the old.
3223         int loadlayout = 1;
3224         std::string sectordir1 = getSectorDir(p2d, 1);
3225         std::string sectordir;
3226         if(fs::PathExists(sectordir1))
3227         {
3228                 sectordir = sectordir1;
3229         }
3230         else
3231         {
3232                 loadlayout = 2;
3233                 sectordir = getSectorDir(p2d, 2);
3234         }
3235
3236         try{
3237                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3238         }
3239         catch(InvalidFilenameException &e)
3240         {
3241                 return false;
3242         }
3243         catch(FileNotGoodException &e)
3244         {
3245                 return false;
3246         }
3247         catch(std::exception &e)
3248         {
3249                 return false;
3250         }
3251         
3252         /*
3253                 Load blocks
3254         */
3255         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3256                         (sectordir);
3257         std::vector<fs::DirListNode>::iterator i2;
3258         for(i2=list2.begin(); i2!=list2.end(); i2++)
3259         {
3260                 // We want files
3261                 if(i2->dir)
3262                         continue;
3263                 try{
3264                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3265                 }
3266                 catch(InvalidFilenameException &e)
3267                 {
3268                         // This catches unknown crap in directory
3269                 }
3270         }
3271
3272         if(loadlayout != 2)
3273         {
3274                 infostream<<"Sector converted to new layout - deleting "<<
3275                         sectordir1<<std::endl;
3276                 fs::RecursiveDelete(sectordir1);
3277         }
3278
3279         return true;
3280 }
3281 #endif
3282
3283 void ServerMap::beginSave() {
3284         verifyDatabase();
3285         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3286                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3287 }
3288
3289 void ServerMap::endSave() {
3290         verifyDatabase();
3291         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3292                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3293 }
3294
3295 void ServerMap::saveBlock(MapBlock *block)
3296 {
3297         DSTACK(__FUNCTION_NAME);
3298         /*
3299                 Dummy blocks are not written
3300         */
3301         if(block->isDummy())
3302         {
3303                 /*v3s16 p = block->getPos();
3304                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3305                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3306                 return;
3307         }
3308
3309         // Format used for writing
3310         u8 version = SER_FMT_VER_HIGHEST;
3311         // Get destination
3312         v3s16 p3d = block->getPos();
3313         
3314         
3315 #if 0
3316         v2s16 p2d(p3d.X, p3d.Z);
3317         std::string sectordir = getSectorDir(p2d);
3318
3319         createDirs(sectordir);
3320
3321         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3322         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3323         if(o.good() == false)
3324                 throw FileNotGoodException("Cannot open block data");
3325 #endif
3326         /*
3327                 [0] u8 serialization version
3328                 [1] data
3329         */
3330         
3331         verifyDatabase();
3332         
3333         std::ostringstream o(std::ios_base::binary);
3334         
3335         o.write((char*)&version, 1);
3336         
3337         // Write basic data
3338         block->serialize(o, version);
3339         
3340         // Write extra data stored on disk
3341         block->serializeDiskExtra(o, version);
3342         
3343         // Write block to database
3344         
3345         std::string tmp = o.str();
3346         const char *bytes = tmp.c_str();
3347         
3348         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
3349                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3350         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
3351                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3352         int written = sqlite3_step(m_database_write);
3353         if(written != SQLITE_DONE)
3354                 infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3355                 <<sqlite3_errmsg(m_database)<<std::endl;
3356         // Make ready for later reuse
3357         sqlite3_reset(m_database_write);
3358         
3359         // We just wrote it to the disk so clear modified flag
3360         block->resetModified();
3361 }
3362
3363 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3364 {
3365         DSTACK(__FUNCTION_NAME);
3366
3367         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3368         try{
3369
3370                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3371                 if(is.good() == false)
3372                         throw FileNotGoodException("Cannot open block file");
3373                 
3374                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3375                 v2s16 p2d(p3d.X, p3d.Z);
3376                 
3377                 assert(sector->getPos() == p2d);
3378                 
3379                 u8 version = SER_FMT_VER_INVALID;
3380                 is.read((char*)&version, 1);
3381
3382                 if(is.fail())
3383                         throw SerializationError("ServerMap::loadBlock(): Failed"
3384                                         " to read MapBlock version");
3385
3386                 /*u32 block_size = MapBlock::serializedLength(version);
3387                 SharedBuffer<u8> data(block_size);
3388                 is.read((char*)*data, block_size);*/
3389
3390                 // This will always return a sector because we're the server
3391                 //MapSector *sector = emergeSector(p2d);
3392
3393                 MapBlock *block = NULL;
3394                 bool created_new = false;
3395                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3396                 if(block == NULL)
3397                 {
3398                         block = sector->createBlankBlockNoInsert(p3d.Y);
3399                         created_new = true;
3400                 }
3401                 
3402                 // Read basic data
3403                 block->deSerialize(is, version);
3404
3405                 // Read extra data stored on disk
3406                 block->deSerializeDiskExtra(is, version);
3407                 
3408                 // If it's a new block, insert it to the map
3409                 if(created_new)
3410                         sector->insertBlock(block);
3411                 
3412                 /*
3413                         Save blocks loaded in old format in new format
3414                 */
3415
3416                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3417                 {
3418                         saveBlock(block);
3419                         
3420                         // Should be in database now, so delete the old file
3421                         fs::RecursiveDelete(fullpath);
3422                 }
3423                 
3424                 // We just loaded it from the disk, so it's up-to-date.
3425                 block->resetModified();
3426
3427         }
3428         catch(SerializationError &e)
3429         {
3430                 infostream<<"WARNING: Invalid block data on disk "
3431                                 <<"fullpath="<<fullpath
3432                                 <<" (SerializationError). "
3433                                 <<"what()="<<e.what()
3434                                 <<std::endl;
3435                                 //" Ignoring. A new one will be generated.
3436                 assert(0);
3437
3438                 // TODO: Backup file; name is in fullpath.
3439         }
3440 }
3441
3442 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3443 {
3444         DSTACK(__FUNCTION_NAME);
3445
3446         try {
3447                 std::istringstream is(*blob, std::ios_base::binary);
3448                 
3449                 u8 version = SER_FMT_VER_INVALID;
3450                 is.read((char*)&version, 1);
3451
3452                 if(is.fail())
3453                         throw SerializationError("ServerMap::loadBlock(): Failed"
3454                                         " to read MapBlock version");
3455
3456                 /*u32 block_size = MapBlock::serializedLength(version);
3457                 SharedBuffer<u8> data(block_size);
3458                 is.read((char*)*data, block_size);*/
3459
3460                 // This will always return a sector because we're the server
3461                 //MapSector *sector = emergeSector(p2d);
3462
3463                 MapBlock *block = NULL;
3464                 bool created_new = false;
3465                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3466                 if(block == NULL)
3467                 {
3468                         block = sector->createBlankBlockNoInsert(p3d.Y);
3469                         created_new = true;
3470                 }
3471                 
3472                 // Read basic data
3473                 block->deSerialize(is, version);
3474
3475                 // Read extra data stored on disk
3476                 block->deSerializeDiskExtra(is, version);
3477                 
3478                 // If it's a new block, insert it to the map
3479                 if(created_new)
3480                         sector->insertBlock(block);
3481                 
3482                 /*
3483                         Save blocks loaded in old format in new format
3484                 */
3485
3486                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3487                 {
3488                         saveBlock(block);
3489                 }
3490                 
3491                 // We just loaded it from, so it's up-to-date.
3492                 block->resetModified();
3493
3494         }
3495         catch(SerializationError &e)
3496         {
3497                 infostream<<"WARNING: Invalid block data in database "
3498                                 <<" (SerializationError). "
3499                                 <<"what()="<<e.what()
3500                                 <<std::endl;
3501                                 //" Ignoring. A new one will be generated.
3502                 assert(0);
3503
3504                 // TODO: Copy to a backup database.
3505         }
3506 }
3507
3508 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3509 {
3510         DSTACK(__FUNCTION_NAME);
3511
3512         v2s16 p2d(blockpos.X, blockpos.Z);
3513
3514         if(!loadFromFolders()) {
3515                 verifyDatabase();
3516                 
3517                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3518                         infostream<<"WARNING: Could not bind block position for load: "
3519                                 <<sqlite3_errmsg(m_database)<<std::endl;
3520                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3521                         /*
3522                                 Make sure sector is loaded
3523                         */
3524                         MapSector *sector = createSector(p2d);
3525                         
3526                         /*
3527                                 Load block
3528                         */
3529                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3530                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3531                         
3532                         std::string datastr(data, len);
3533                         
3534                         loadBlock(&datastr, blockpos, sector, false);
3535
3536                         sqlite3_step(m_database_read);
3537                         // We should never get more than 1 row, so ok to reset
3538                         sqlite3_reset(m_database_read);
3539
3540                         return getBlockNoCreateNoEx(blockpos);
3541                 }
3542                 sqlite3_reset(m_database_read);
3543                 
3544                 // Not found in database, try the files
3545         }
3546
3547         // The directory layout we're going to load from.
3548         //  1 - original sectors/xxxxzzzz/
3549         //  2 - new sectors2/xxx/zzz/
3550         //  If we load from anything but the latest structure, we will
3551         //  immediately save to the new one, and remove the old.
3552         int loadlayout = 1;
3553         std::string sectordir1 = getSectorDir(p2d, 1);
3554         std::string sectordir;
3555         if(fs::PathExists(sectordir1))
3556         {
3557                 sectordir = sectordir1;
3558         }
3559         else
3560         {
3561                 loadlayout = 2;
3562                 sectordir = getSectorDir(p2d, 2);
3563         }
3564         
3565         /*
3566                 Make sure sector is loaded
3567         */
3568         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3569         if(sector == NULL)
3570         {
3571                 try{
3572                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3573                 }
3574                 catch(InvalidFilenameException &e)
3575                 {
3576                         return false;
3577                 }
3578                 catch(FileNotGoodException &e)
3579                 {
3580                         return false;
3581                 }
3582                 catch(std::exception &e)
3583                 {
3584                         return false;
3585                 }
3586         }
3587         
3588         /*
3589                 Make sure file exists
3590         */
3591
3592         std::string blockfilename = getBlockFilename(blockpos);
3593         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3594                 return NULL;
3595
3596         /*
3597                 Load block and save it to the database
3598         */
3599         loadBlock(sectordir, blockfilename, sector, true);
3600         return getBlockNoCreateNoEx(blockpos);
3601 }
3602
3603 void ServerMap::PrintInfo(std::ostream &out)
3604 {
3605         out<<"ServerMap: ";
3606 }
3607
3608 #ifndef SERVER
3609
3610 /*
3611         ClientMap
3612 */
3613
3614 ClientMap::ClientMap(
3615                 Client *client,
3616                 MapDrawControl &control,
3617                 scene::ISceneNode* parent,
3618                 scene::ISceneManager* mgr,
3619                 s32 id
3620 ):
3621         Map(dout_client),
3622         scene::ISceneNode(parent, mgr, id),
3623         m_client(client),
3624         m_control(control),
3625         m_camera_position(0,0,0),
3626         m_camera_direction(0,0,1),
3627         m_camera_fov(PI)
3628 {
3629         m_camera_mutex.Init();
3630         assert(m_camera_mutex.IsInitialized());
3631         
3632         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3633                         BS*1000000,BS*1000000,BS*1000000);
3634 }
3635
3636 ClientMap::~ClientMap()
3637 {
3638         /*JMutexAutoLock lock(mesh_mutex);
3639         
3640         if(mesh != NULL)
3641         {
3642                 mesh->drop();
3643                 mesh = NULL;
3644         }*/
3645 }
3646
3647 MapSector * ClientMap::emergeSector(v2s16 p2d)
3648 {
3649         DSTACK(__FUNCTION_NAME);
3650         // Check that it doesn't exist already
3651         try{
3652                 return getSectorNoGenerate(p2d);
3653         }
3654         catch(InvalidPositionException &e)
3655         {
3656         }
3657         
3658         // Create a sector
3659         ClientMapSector *sector = new ClientMapSector(this, p2d);
3660         
3661         {
3662                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3663                 m_sectors.insert(p2d, sector);
3664         }
3665         
3666         return sector;
3667 }
3668
3669 #if 0
3670 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3671 {
3672         DSTACK(__FUNCTION_NAME);
3673         ClientMapSector *sector = NULL;
3674
3675         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3676         
3677         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3678
3679         if(n != NULL)
3680         {
3681                 sector = (ClientMapSector*)n->getValue();
3682                 assert(sector->getId() == MAPSECTOR_CLIENT);
3683         }
3684         else
3685         {
3686                 sector = new ClientMapSector(this, p2d);
3687                 {
3688                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3689                         m_sectors.insert(p2d, sector);
3690                 }
3691         }
3692
3693         sector->deSerialize(is);
3694 }
3695 #endif
3696
3697 void ClientMap::OnRegisterSceneNode()
3698 {
3699         if(IsVisible)
3700         {
3701                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3702                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3703         }
3704
3705         ISceneNode::OnRegisterSceneNode();
3706 }
3707
3708 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3709 {
3710         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3711         DSTACK(__FUNCTION_NAME);
3712
3713         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3714         
3715         /*
3716                 This is called two times per frame, reset on the non-transparent one
3717         */
3718         if(pass == scene::ESNRP_SOLID)
3719         {
3720                 m_last_drawn_sectors.clear();
3721         }
3722
3723         /*
3724                 Get time for measuring timeout.
3725                 
3726                 Measuring time is very useful for long delays when the
3727                 machine is swapping a lot.
3728         */
3729         int time1 = time(0);
3730
3731         //u32 daynight_ratio = m_client->getDayNightRatio();
3732
3733         m_camera_mutex.Lock();
3734         v3f camera_position = m_camera_position;
3735         v3f camera_direction = m_camera_direction;
3736         f32 camera_fov = m_camera_fov;
3737         m_camera_mutex.Unlock();
3738
3739         /*
3740                 Get all blocks and draw all visible ones
3741         */
3742
3743         v3s16 cam_pos_nodes(
3744                         camera_position.X / BS,
3745                         camera_position.Y / BS,
3746                         camera_position.Z / BS);
3747
3748         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3749
3750         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3751         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3752
3753         // Take a fair amount as we will be dropping more out later
3754         v3s16 p_blocks_min(
3755                         p_nodes_min.X / MAP_BLOCKSIZE - 2,
3756                         p_nodes_min.Y / MAP_BLOCKSIZE - 2,
3757                         p_nodes_min.Z / MAP_BLOCKSIZE - 2);
3758         v3s16 p_blocks_max(
3759                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3760                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3761                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3762         
3763         u32 vertex_count = 0;
3764         u32 meshbuffer_count = 0;
3765         
3766         // For limiting number of mesh updates per frame
3767         u32 mesh_update_count = 0;
3768         
3769         u32 blocks_would_have_drawn = 0;
3770         u32 blocks_drawn = 0;
3771
3772         int timecheck_counter = 0;
3773         core::map<v2s16, MapSector*>::Iterator si;
3774         si = m_sectors.getIterator();
3775         for(; si.atEnd() == false; si++)
3776         {
3777                 {
3778                         timecheck_counter++;
3779                         if(timecheck_counter > 50)
3780                         {
3781                                 timecheck_counter = 0;
3782                                 int time2 = time(0);
3783                                 if(time2 > time1 + 4)
3784                                 {
3785                                         infostream<<"ClientMap::renderMap(): "
3786                                                 "Rendering takes ages, returning."
3787                                                 <<std::endl;
3788                                         return;
3789                                 }
3790                         }
3791                 }
3792
3793                 MapSector *sector = si.getNode()->getValue();
3794                 v2s16 sp = sector->getPos();
3795                 
3796                 if(m_control.range_all == false)
3797                 {
3798                         if(sp.X < p_blocks_min.X
3799                         || sp.X > p_blocks_max.X
3800                         || sp.Y < p_blocks_min.Z
3801                         || sp.Y > p_blocks_max.Z)
3802                                 continue;
3803                 }
3804
3805                 core::list< MapBlock * > sectorblocks;
3806                 sector->getBlocks(sectorblocks);
3807                 
3808                 /*
3809                         Draw blocks
3810                 */
3811                 
3812                 u32 sector_blocks_drawn = 0;
3813
3814                 core::list< MapBlock * >::Iterator i;
3815                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3816                 {
3817                         MapBlock *block = *i;
3818
3819                         /*
3820                                 Compare block position to camera position, skip
3821                                 if not seen on display
3822                         */
3823                         
3824                         float range = 100000 * BS;
3825                         if(m_control.range_all == false)
3826                                 range = m_control.wanted_range * BS;
3827                         
3828                         float d = 0.0;
3829                         if(isBlockInSight(block->getPos(), camera_position,
3830                                         camera_direction, camera_fov,
3831                                         range, &d) == false)
3832                         {
3833                                 continue;
3834                         }
3835
3836                         // Okay, this block will be drawn. Reset usage timer.
3837                         block->resetUsageTimer();
3838                         
3839                         // This is ugly (spherical distance limit?)
3840                         /*if(m_control.range_all == false &&
3841                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3842                                 continue;*/
3843
3844 #if 1
3845                         /*
3846                                 Update expired mesh (used for day/night change)
3847
3848                                 It doesn't work exactly like it should now with the
3849                                 tasked mesh update but whatever.
3850                         */
3851
3852                         bool mesh_expired = false;
3853                         
3854                         {
3855                                 JMutexAutoLock lock(block->mesh_mutex);
3856
3857                                 mesh_expired = block->getMeshExpired();
3858
3859                                 // Mesh has not been expired and there is no mesh:
3860                                 // block has no content
3861                                 if(block->mesh == NULL && mesh_expired == false)
3862                                         continue;
3863                         }
3864
3865                         f32 faraway = BS*50;
3866                         //f32 faraway = m_control.wanted_range * BS;
3867                         
3868                         /*
3869                                 This has to be done with the mesh_mutex unlocked
3870                         */
3871                         // Pretty random but this should work somewhat nicely
3872                         if(mesh_expired && (
3873                                         (mesh_update_count < 3
3874                                                 && (d < faraway || mesh_update_count < 2)
3875                                         )
3876                                         || 
3877                                         (m_control.range_all && mesh_update_count < 20)
3878                                 )
3879                         )
3880                         /*if(mesh_expired && mesh_update_count < 6
3881                                         && (d < faraway || mesh_update_count < 3))*/
3882                         {
3883                                 mesh_update_count++;
3884
3885                                 // Mesh has been expired: generate new mesh
3886                                 //block->updateMesh(daynight_ratio);
3887                                 m_client->addUpdateMeshTask(block->getPos());
3888
3889                                 mesh_expired = false;
3890                         }
3891                         
3892 #endif
3893                         /*
3894                                 Draw the faces of the block
3895                         */
3896                         {
3897                                 JMutexAutoLock lock(block->mesh_mutex);
3898
3899                                 scene::SMesh *mesh = block->mesh;
3900
3901                                 if(mesh == NULL)
3902                                         continue;
3903                                 
3904                                 blocks_would_have_drawn++;
3905                                 if(blocks_drawn >= m_control.wanted_max_blocks
3906                                                 && m_control.range_all == false
3907                                                 && d > m_control.wanted_min_range * BS)
3908                                         continue;
3909
3910                                 blocks_drawn++;
3911                                 sector_blocks_drawn++;
3912
3913                                 u32 c = mesh->getMeshBufferCount();
3914                                 meshbuffer_count += c;
3915
3916                                 for(u32 i=0; i<c; i++)
3917                                 {
3918                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3919                                         const video::SMaterial& material = buf->getMaterial();
3920                                         video::IMaterialRenderer* rnd =
3921                                                         driver->getMaterialRenderer(material.MaterialType);
3922                                         bool transparent = (rnd && rnd->isTransparent());
3923                                         // Render transparent on transparent pass and likewise.
3924                                         if(transparent == is_transparent_pass)
3925                                         {
3926                                                 /*
3927                                                         This *shouldn't* hurt too much because Irrlicht
3928                                                         doesn't change opengl textures if the old
3929                                                         material is set again.
3930                                                 */
3931                                                 driver->setMaterial(buf->getMaterial());
3932                                                 driver->drawMeshBuffer(buf);
3933                                                 vertex_count += buf->getVertexCount();
3934                                         }
3935                                 }
3936                         }
3937                 } // foreach sectorblocks
3938
3939                 if(sector_blocks_drawn != 0)
3940                 {
3941                         m_last_drawn_sectors[sp] = true;
3942                 }
3943         }
3944         
3945         if(pass == scene::ESNRP_SOLID){
3946                 g_profiler->avg("CM: blocks drawn on solid pass", blocks_drawn);
3947                 g_profiler->avg("CM: vertices drawn on solid pass", vertex_count);
3948                 if(blocks_drawn != 0)
3949                         g_profiler->avg("CM: solid meshbuffers per block",
3950                                         (float)meshbuffer_count / (float)blocks_drawn);
3951         } else {
3952                 g_profiler->avg("CM: blocks drawn on transparent pass", blocks_drawn);
3953                 g_profiler->avg("CM: vertices drawn on transparent pass", vertex_count);
3954         }
3955         
3956         m_control.blocks_drawn = blocks_drawn;
3957         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3958
3959         /*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3960                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3961 }
3962
3963 void ClientMap::renderPostFx()
3964 {
3965         // Sadly ISceneManager has no "post effects" render pass, in that case we
3966         // could just register for that and handle it in renderMap().
3967
3968         m_camera_mutex.Lock();
3969         v3f camera_position = m_camera_position;
3970         m_camera_mutex.Unlock();
3971
3972         MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
3973
3974         // - If the player is in a solid node, make everything black.
3975         // - If the player is in liquid, draw a semi-transparent overlay.
3976         ContentFeatures& features = content_features(n);
3977         video::SColor post_effect_color = features.post_effect_color;
3978         if(features.solidness == 2 && g_settings->getBool("free_move") == false)
3979         {
3980                 post_effect_color = video::SColor(255, 0, 0, 0);
3981         }
3982         if (post_effect_color.getAlpha() != 0)
3983         {
3984                 // Draw a full-screen rectangle
3985                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
3986                 v2u32 ss = driver->getScreenSize();
3987                 core::rect<s32> rect(0,0, ss.X, ss.Y);
3988                 driver->draw2DRectangle(post_effect_color, rect);
3989         }
3990 }
3991
3992 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
3993                 core::map<v3s16, MapBlock*> *affected_blocks)
3994 {
3995         bool changed = false;
3996         /*
3997                 Add it to all blocks touching it
3998         */
3999         v3s16 dirs[7] = {
4000                 v3s16(0,0,0), // this
4001                 v3s16(0,0,1), // back
4002                 v3s16(0,1,0), // top
4003                 v3s16(1,0,0), // right
4004                 v3s16(0,0,-1), // front
4005                 v3s16(0,-1,0), // bottom
4006                 v3s16(-1,0,0), // left
4007         };
4008         for(u16 i=0; i<7; i++)
4009         {
4010                 v3s16 p2 = p + dirs[i];
4011                 // Block position of neighbor (or requested) node
4012                 v3s16 blockpos = getNodeBlockPos(p2);
4013                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4014                 if(blockref == NULL)
4015                         continue;
4016                 // Relative position of requested node
4017                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4018                 if(blockref->setTempMod(relpos, mod))
4019                 {
4020                         changed = true;
4021                 }
4022         }
4023         if(changed && affected_blocks!=NULL)
4024         {
4025                 for(u16 i=0; i<7; i++)
4026                 {
4027                         v3s16 p2 = p + dirs[i];
4028                         // Block position of neighbor (or requested) node
4029                         v3s16 blockpos = getNodeBlockPos(p2);
4030                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4031                         if(blockref == NULL)
4032                                 continue;
4033                         affected_blocks->insert(blockpos, blockref);
4034                 }
4035         }
4036         return changed;
4037 }
4038
4039 bool ClientMap::clearTempMod(v3s16 p,
4040                 core::map<v3s16, MapBlock*> *affected_blocks)
4041 {
4042         bool changed = false;
4043         v3s16 dirs[7] = {
4044                 v3s16(0,0,0), // this
4045                 v3s16(0,0,1), // back
4046                 v3s16(0,1,0), // top
4047                 v3s16(1,0,0), // right
4048                 v3s16(0,0,-1), // front
4049                 v3s16(0,-1,0), // bottom
4050                 v3s16(-1,0,0), // left
4051         };
4052         for(u16 i=0; i<7; i++)
4053         {
4054                 v3s16 p2 = p + dirs[i];
4055                 // Block position of neighbor (or requested) node
4056                 v3s16 blockpos = getNodeBlockPos(p2);
4057                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4058                 if(blockref == NULL)
4059                         continue;
4060                 // Relative position of requested node
4061                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4062                 if(blockref->clearTempMod(relpos))
4063                 {
4064                         changed = true;
4065                 }
4066         }
4067         if(changed && affected_blocks!=NULL)
4068         {
4069                 for(u16 i=0; i<7; i++)
4070                 {
4071                         v3s16 p2 = p + dirs[i];
4072                         // Block position of neighbor (or requested) node
4073                         v3s16 blockpos = getNodeBlockPos(p2);
4074                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4075                         if(blockref == NULL)
4076                                 continue;
4077                         affected_blocks->insert(blockpos, blockref);
4078                 }
4079         }
4080         return changed;
4081 }
4082
4083 void ClientMap::expireMeshes(bool only_daynight_diffed)
4084 {
4085         TimeTaker timer("expireMeshes()");
4086
4087         core::map<v2s16, MapSector*>::Iterator si;
4088         si = m_sectors.getIterator();
4089         for(; si.atEnd() == false; si++)
4090         {
4091                 MapSector *sector = si.getNode()->getValue();
4092
4093                 core::list< MapBlock * > sectorblocks;
4094                 sector->getBlocks(sectorblocks);
4095                 
4096                 core::list< MapBlock * >::Iterator i;
4097                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
4098                 {
4099                         MapBlock *block = *i;
4100
4101                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
4102                         {
4103                                 continue;
4104                         }
4105                         
4106                         {
4107                                 JMutexAutoLock lock(block->mesh_mutex);
4108                                 if(block->mesh != NULL)
4109                                 {
4110                                         /*block->mesh->drop();
4111                                         block->mesh = NULL;*/
4112                                         block->setMeshExpired(true);
4113                                 }
4114                         }
4115                 }
4116         }
4117 }
4118
4119 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
4120 {
4121         assert(mapType() == MAPTYPE_CLIENT);
4122
4123         try{
4124                 v3s16 p = blockpos + v3s16(0,0,0);
4125                 MapBlock *b = getBlockNoCreate(p);
4126                 b->updateMesh(daynight_ratio);
4127                 //b->setMeshExpired(true);
4128         }
4129         catch(InvalidPositionException &e){}
4130         // Leading edge
4131         try{
4132                 v3s16 p = blockpos + v3s16(-1,0,0);
4133                 MapBlock *b = getBlockNoCreate(p);
4134                 b->updateMesh(daynight_ratio);
4135                 //b->setMeshExpired(true);
4136         }
4137         catch(InvalidPositionException &e){}
4138         try{
4139                 v3s16 p = blockpos + v3s16(0,-1,0);
4140                 MapBlock *b = getBlockNoCreate(p);
4141                 b->updateMesh(daynight_ratio);
4142                 //b->setMeshExpired(true);
4143         }
4144         catch(InvalidPositionException &e){}
4145         try{
4146                 v3s16 p = blockpos + v3s16(0,0,-1);
4147                 MapBlock *b = getBlockNoCreate(p);
4148                 b->updateMesh(daynight_ratio);
4149                 //b->setMeshExpired(true);
4150         }
4151         catch(InvalidPositionException &e){}
4152 }
4153
4154 #if 0
4155 /*
4156         Update mesh of block in which the node is, and if the node is at the
4157         leading edge, update the appropriate leading blocks too.
4158 */
4159 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
4160 {
4161         v3s16 dirs[4] = {
4162                 v3s16(0,0,0),
4163                 v3s16(-1,0,0),
4164                 v3s16(0,-1,0),
4165                 v3s16(0,0,-1),
4166         };
4167         v3s16 blockposes[4];
4168         for(u32 i=0; i<4; i++)
4169         {
4170                 v3s16 np = nodepos + dirs[i];
4171                 blockposes[i] = getNodeBlockPos(np);
4172                 // Don't update mesh of block if it has been done already
4173                 bool already_updated = false;
4174                 for(u32 j=0; j<i; j++)
4175                 {
4176                         if(blockposes[j] == blockposes[i])
4177                         {
4178                                 already_updated = true;
4179                                 break;
4180                         }
4181                 }
4182                 if(already_updated)
4183                         continue;
4184                 // Update mesh
4185                 MapBlock *b = getBlockNoCreate(blockposes[i]);
4186                 b->updateMesh(daynight_ratio);
4187         }
4188 }
4189 #endif
4190
4191 void ClientMap::PrintInfo(std::ostream &out)
4192 {
4193         out<<"ClientMap: ";
4194 }
4195
4196 #endif // !SERVER
4197
4198 /*
4199         MapVoxelManipulator
4200 */
4201
4202 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4203 {
4204         m_map = map;
4205 }
4206
4207 MapVoxelManipulator::~MapVoxelManipulator()
4208 {
4209         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4210                         <<std::endl;*/
4211 }
4212
4213 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4214 {
4215         TimeTaker timer1("emerge", &emerge_time);
4216
4217         // Units of these are MapBlocks
4218         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4219         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4220
4221         VoxelArea block_area_nodes
4222                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4223
4224         addArea(block_area_nodes);
4225
4226         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4227         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4228         for(s32 x=p_min.X; x<=p_max.X; x++)
4229         {
4230                 v3s16 p(x,y,z);
4231                 core::map<v3s16, bool>::Node *n;
4232                 n = m_loaded_blocks.find(p);
4233                 if(n != NULL)
4234                         continue;
4235                 
4236                 bool block_data_inexistent = false;
4237                 try
4238                 {
4239                         TimeTaker timer1("emerge load", &emerge_load_time);
4240
4241                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4242                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4243                                         <<" wanted area: ";
4244                         a.print(infostream);
4245                         infostream<<std::endl;*/
4246                         
4247                         MapBlock *block = m_map->getBlockNoCreate(p);
4248                         if(block->isDummy())
4249                                 block_data_inexistent = true;
4250                         else
4251                                 block->copyTo(*this);
4252                 }
4253                 catch(InvalidPositionException &e)
4254                 {
4255                         block_data_inexistent = true;
4256                 }
4257
4258                 if(block_data_inexistent)
4259                 {
4260                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4261                         // Fill with VOXELFLAG_INEXISTENT
4262                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4263                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4264                         {
4265                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4266                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4267                         }
4268                 }
4269
4270                 m_loaded_blocks.insert(p, !block_data_inexistent);
4271         }
4272
4273         //infostream<<"emerge done"<<std::endl;
4274 }
4275
4276 /*
4277         SUGG: Add an option to only update eg. water and air nodes.
4278               This will make it interfere less with important stuff if
4279                   run on background.
4280 */
4281 void MapVoxelManipulator::blitBack
4282                 (core::map<v3s16, MapBlock*> & modified_blocks)
4283 {
4284         if(m_area.getExtent() == v3s16(0,0,0))
4285                 return;
4286         
4287         //TimeTaker timer1("blitBack");
4288
4289         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4290                         <<m_loaded_blocks.size()<<std::endl;*/
4291         
4292         /*
4293                 Initialize block cache
4294         */
4295         v3s16 blockpos_last;
4296         MapBlock *block = NULL;
4297         bool block_checked_in_modified = false;
4298
4299         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4300         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4301         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4302         {
4303                 v3s16 p(x,y,z);
4304
4305                 u8 f = m_flags[m_area.index(p)];
4306                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4307                         continue;
4308
4309                 MapNode &n = m_data[m_area.index(p)];
4310                         
4311                 v3s16 blockpos = getNodeBlockPos(p);
4312                 
4313                 try
4314                 {
4315                         // Get block
4316                         if(block == NULL || blockpos != blockpos_last){
4317                                 block = m_map->getBlockNoCreate(blockpos);
4318                                 blockpos_last = blockpos;
4319                                 block_checked_in_modified = false;
4320                         }
4321                         
4322                         // Calculate relative position in block
4323                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4324
4325                         // Don't continue if nothing has changed here
4326                         if(block->getNode(relpos) == n)
4327                                 continue;
4328
4329                         //m_map->setNode(m_area.MinEdge + p, n);
4330                         block->setNode(relpos, n);
4331                         
4332                         /*
4333                                 Make sure block is in modified_blocks
4334                         */
4335                         if(block_checked_in_modified == false)
4336                         {
4337                                 modified_blocks[blockpos] = block;
4338                                 block_checked_in_modified = true;
4339                         }
4340                 }
4341                 catch(InvalidPositionException &e)
4342                 {
4343                 }
4344         }
4345 }
4346
4347 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4348                 MapVoxelManipulator(map),
4349                 m_create_area(false)
4350 {
4351 }
4352
4353 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4354 {
4355 }
4356
4357 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4358 {
4359         // Just create the area so that it can be pointed to
4360         VoxelManipulator::emerge(a, caller_id);
4361 }
4362
4363 void ManualMapVoxelManipulator::initialEmerge(
4364                 v3s16 blockpos_min, v3s16 blockpos_max)
4365 {
4366         TimeTaker timer1("initialEmerge", &emerge_time);
4367
4368         // Units of these are MapBlocks
4369         v3s16 p_min = blockpos_min;
4370         v3s16 p_max = blockpos_max;
4371
4372         VoxelArea block_area_nodes
4373                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4374         
4375         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4376         if(size_MB >= 1)
4377         {
4378                 infostream<<"initialEmerge: area: ";
4379                 block_area_nodes.print(infostream);
4380                 infostream<<" ("<<size_MB<<"MB)";
4381                 infostream<<std::endl;
4382         }
4383
4384         addArea(block_area_nodes);
4385
4386         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4387         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4388         for(s32 x=p_min.X; x<=p_max.X; x++)
4389         {
4390                 v3s16 p(x,y,z);
4391                 core::map<v3s16, bool>::Node *n;
4392                 n = m_loaded_blocks.find(p);
4393                 if(n != NULL)
4394                         continue;
4395                 
4396                 bool block_data_inexistent = false;
4397                 try
4398                 {
4399                         TimeTaker timer1("emerge load", &emerge_load_time);
4400
4401                         MapBlock *block = m_map->getBlockNoCreate(p);
4402                         if(block->isDummy())
4403                                 block_data_inexistent = true;
4404                         else
4405                                 block->copyTo(*this);
4406                 }
4407                 catch(InvalidPositionException &e)
4408                 {
4409                         block_data_inexistent = true;
4410                 }
4411
4412                 if(block_data_inexistent)
4413                 {
4414                         /*
4415                                 Mark area inexistent
4416                         */
4417                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4418                         // Fill with VOXELFLAG_INEXISTENT
4419                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4420                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4421                         {
4422                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4423                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4424                         }
4425                 }
4426
4427                 m_loaded_blocks.insert(p, !block_data_inexistent);
4428         }
4429 }
4430
4431 void ManualMapVoxelManipulator::blitBackAll(
4432                 core::map<v3s16, MapBlock*> * modified_blocks)
4433 {
4434         if(m_area.getExtent() == v3s16(0,0,0))
4435                 return;
4436         
4437         /*
4438                 Copy data of all blocks
4439         */
4440         for(core::map<v3s16, bool>::Iterator
4441                         i = m_loaded_blocks.getIterator();
4442                         i.atEnd() == false; i++)
4443         {
4444                 v3s16 p = i.getNode()->getKey();
4445                 bool existed = i.getNode()->getValue();
4446                 if(existed == false)
4447                 {
4448                         // The Great Bug was found using this
4449                         /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
4450                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4451                                         <<std::endl;*/
4452                         continue;
4453                 }
4454                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4455                 if(block == NULL)
4456                 {
4457                         infostream<<"WARNING: "<<__FUNCTION_NAME
4458                                         <<": got NULL block "
4459                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4460                                         <<std::endl;
4461                         continue;
4462                 }
4463
4464                 block->copyFrom(*this);
4465
4466                 if(modified_blocks)
4467                         modified_blocks->insert(p, block);
4468         }
4469 }
4470
4471 //END