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