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