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