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