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