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