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