13f2a0e984d0ab13e951fa07255de4b8b2738ab2
[oweals/minetest.git] / src / map.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "mapsector.h"
22 #include "mapblock.h"
23 #include "main.h"
24 #ifndef SERVER
25 #include "client.h"
26 #endif
27 #include "filesys.h"
28 #include "utility.h"
29 #include "voxel.h"
30 #include "porting.h"
31 #include "mapgen.h"
32 #include "nodemetadata.h"
33 #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         beginSave();
2840         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2841         for(; i.atEnd() == false; i++)
2842         {
2843                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2844                 assert(sector->getId() == MAPSECTOR_SERVER);
2845         
2846                 if(sector->differs_from_disk || only_changed == false)
2847                 {
2848                         saveSectorMeta(sector);
2849                         sector_meta_count++;
2850                 }
2851                 core::list<MapBlock*> blocks;
2852                 sector->getBlocks(blocks);
2853                 core::list<MapBlock*>::Iterator j;
2854                 
2855                 //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL);
2856                 for(j=blocks.begin(); j!=blocks.end(); j++)
2857                 {
2858                         MapBlock *block = *j;
2859                         
2860                         block_count_all++;
2861
2862                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
2863                                         || only_changed == false)
2864                         {
2865                                 modprofiler.add(block->getModifiedReason(), 1);
2866                                 saveBlock(block);
2867                                 block_count++;
2868
2869                                 /*infostream<<"ServerMap: Written block ("
2870                                                 <<block->getPos().X<<","
2871                                                 <<block->getPos().Y<<","
2872                                                 <<block->getPos().Z<<")"
2873                                                 <<std::endl;*/
2874                         }
2875                 //sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL);
2876                 }
2877         }
2878         endSave();
2879
2880         /*
2881                 Only print if something happened or saved whole map
2882         */
2883         if(only_changed == false || sector_meta_count != 0
2884                         || block_count != 0)
2885         {
2886                 infostream<<"ServerMap: Written: "
2887                                 <<sector_meta_count<<" sector metadata files, "
2888                                 <<block_count<<" block files"
2889                                 <<", "<<block_count_all<<" blocks in memory."
2890                                 <<std::endl;
2891                 PrintInfo(infostream); // ServerMap/ClientMap:
2892                 infostream<<"Blocks modified by: "<<std::endl;
2893                 modprofiler.print(infostream);
2894         }
2895 }
2896
2897 static s32 unsignedToSigned(s32 i, s32 max_positive)
2898 {
2899         if(i < max_positive)
2900                 return i;
2901         else
2902                 return i - 2*max_positive;
2903 }
2904
2905 // modulo of a negative number does not work consistently in C
2906 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
2907 {
2908         if(i >= 0)
2909                 return i % mod;
2910         return mod - ((-i) % mod);
2911 }
2912
2913 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
2914 {
2915         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2916         i = (i - x) / 4096;
2917         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2918         i = (i - y) / 4096;
2919         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2920         return v3s16(x,y,z);
2921 }
2922
2923 void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
2924 {
2925         if(loadFromFolders()){
2926                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
2927                                 <<"all blocks that are stored in flat files"<<std::endl;
2928         }
2929         
2930         {
2931                 verifyDatabase();
2932                 
2933                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
2934                 {
2935                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
2936                         v3s16 p = getIntegerAsBlock(block_i);
2937                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
2938                         dst.push_back(p);
2939                 }
2940         }
2941 }
2942
2943 void ServerMap::saveMapMeta()
2944 {
2945         DSTACK(__FUNCTION_NAME);
2946         
2947         infostream<<"ServerMap::saveMapMeta(): "
2948                         <<"seed="<<m_seed
2949                         <<std::endl;
2950
2951         createDirs(m_savedir);
2952         
2953         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
2954         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
2955         if(os.good() == false)
2956         {
2957                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
2958                                 <<"could not open"<<fullpath<<std::endl;
2959                 throw FileNotGoodException("Cannot open chunk metadata");
2960         }
2961         
2962         Settings params;
2963         params.setU64("seed", m_seed);
2964
2965         params.writeLines(os);
2966
2967         os<<"[end_of_params]\n";
2968         
2969         m_map_metadata_changed = false;
2970 }
2971
2972 void ServerMap::loadMapMeta()
2973 {
2974         DSTACK(__FUNCTION_NAME);
2975         
2976         infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
2977                         <<std::endl;
2978
2979         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
2980         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2981         if(is.good() == false)
2982         {
2983                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
2984                                 <<"could not open"<<fullpath<<std::endl;
2985                 throw FileNotGoodException("Cannot open map metadata");
2986         }
2987
2988         Settings params;
2989
2990         for(;;)
2991         {
2992                 if(is.eof())
2993                         throw SerializationError
2994                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
2995                 std::string line;
2996                 std::getline(is, line);
2997                 std::string trimmedline = trim(line);
2998                 if(trimmedline == "[end_of_params]")
2999                         break;
3000                 params.parseConfigLine(line);
3001         }
3002
3003         m_seed = params.getU64("seed");
3004
3005         infostream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3006 }
3007
3008 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3009 {
3010         DSTACK(__FUNCTION_NAME);
3011         // Format used for writing
3012         u8 version = SER_FMT_VER_HIGHEST;
3013         // Get destination
3014         v2s16 pos = sector->getPos();
3015         std::string dir = getSectorDir(pos);
3016         createDirs(dir);
3017         
3018         std::string fullpath = dir + DIR_DELIM + "meta";
3019         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3020         if(o.good() == false)
3021                 throw FileNotGoodException("Cannot open sector metafile");
3022
3023         sector->serialize(o, version);
3024         
3025         sector->differs_from_disk = false;
3026 }
3027
3028 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3029 {
3030         DSTACK(__FUNCTION_NAME);
3031         // Get destination
3032         v2s16 p2d = getSectorPos(sectordir);
3033
3034         ServerMapSector *sector = NULL;
3035
3036         std::string fullpath = sectordir + DIR_DELIM + "meta";
3037         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3038         if(is.good() == false)
3039         {
3040                 // If the directory exists anyway, it probably is in some old
3041                 // format. Just go ahead and create the sector.
3042                 if(fs::PathExists(sectordir))
3043                 {
3044                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3045                                         <<fullpath<<" doesn't exist but directory does."
3046                                         <<" Continuing with a sector with no metadata."
3047                                         <<std::endl;*/
3048                         sector = new ServerMapSector(this, p2d, m_gamedef);
3049                         m_sectors.insert(p2d, sector);
3050                 }
3051                 else
3052                 {
3053                         throw FileNotGoodException("Cannot open sector metafile");
3054                 }
3055         }
3056         else
3057         {
3058                 sector = ServerMapSector::deSerialize
3059                                 (is, this, p2d, m_sectors, m_gamedef);
3060                 if(save_after_load)
3061                         saveSectorMeta(sector);
3062         }
3063         
3064         sector->differs_from_disk = false;
3065
3066         return sector;
3067 }
3068
3069 bool ServerMap::loadSectorMeta(v2s16 p2d)
3070 {
3071         DSTACK(__FUNCTION_NAME);
3072
3073         MapSector *sector = NULL;
3074
3075         // The directory layout we're going to load from.
3076         //  1 - original sectors/xxxxzzzz/
3077         //  2 - new sectors2/xxx/zzz/
3078         //  If we load from anything but the latest structure, we will
3079         //  immediately save to the new one, and remove the old.
3080         int loadlayout = 1;
3081         std::string sectordir1 = getSectorDir(p2d, 1);
3082         std::string sectordir;
3083         if(fs::PathExists(sectordir1))
3084         {
3085                 sectordir = sectordir1;
3086         }
3087         else
3088         {
3089                 loadlayout = 2;
3090                 sectordir = getSectorDir(p2d, 2);
3091         }
3092
3093         try{
3094                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3095         }
3096         catch(InvalidFilenameException &e)
3097         {
3098                 return false;
3099         }
3100         catch(FileNotGoodException &e)
3101         {
3102                 return false;
3103         }
3104         catch(std::exception &e)
3105         {
3106                 return false;
3107         }
3108         
3109         return true;
3110 }
3111
3112 #if 0
3113 bool ServerMap::loadSectorFull(v2s16 p2d)
3114 {
3115         DSTACK(__FUNCTION_NAME);
3116
3117         MapSector *sector = NULL;
3118
3119         // The directory layout we're going to load from.
3120         //  1 - original sectors/xxxxzzzz/
3121         //  2 - new sectors2/xxx/zzz/
3122         //  If we load from anything but the latest structure, we will
3123         //  immediately save to the new one, and remove the old.
3124         int loadlayout = 1;
3125         std::string sectordir1 = getSectorDir(p2d, 1);
3126         std::string sectordir;
3127         if(fs::PathExists(sectordir1))
3128         {
3129                 sectordir = sectordir1;
3130         }
3131         else
3132         {
3133                 loadlayout = 2;
3134                 sectordir = getSectorDir(p2d, 2);
3135         }
3136
3137         try{
3138                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3139         }
3140         catch(InvalidFilenameException &e)
3141         {
3142                 return false;
3143         }
3144         catch(FileNotGoodException &e)
3145         {
3146                 return false;
3147         }
3148         catch(std::exception &e)
3149         {
3150                 return false;
3151         }
3152         
3153         /*
3154                 Load blocks
3155         */
3156         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3157                         (sectordir);
3158         std::vector<fs::DirListNode>::iterator i2;
3159         for(i2=list2.begin(); i2!=list2.end(); i2++)
3160         {
3161                 // We want files
3162                 if(i2->dir)
3163                         continue;
3164                 try{
3165                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3166                 }
3167                 catch(InvalidFilenameException &e)
3168                 {
3169                         // This catches unknown crap in directory
3170                 }
3171         }
3172
3173         if(loadlayout != 2)
3174         {
3175                 infostream<<"Sector converted to new layout - deleting "<<
3176                         sectordir1<<std::endl;
3177                 fs::RecursiveDelete(sectordir1);
3178         }
3179
3180         return true;
3181 }
3182 #endif
3183
3184 void ServerMap::beginSave() {
3185         verifyDatabase();
3186         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3187                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3188 }
3189
3190 void ServerMap::endSave() {
3191         verifyDatabase();
3192         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3193                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3194 }
3195
3196 void ServerMap::saveBlock(MapBlock *block)
3197 {
3198         DSTACK(__FUNCTION_NAME);
3199         /*
3200                 Dummy blocks are not written
3201         */
3202         if(block->isDummy())
3203         {
3204                 /*v3s16 p = block->getPos();
3205                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3206                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3207                 return;
3208         }
3209
3210         // Format used for writing
3211         u8 version = SER_FMT_VER_HIGHEST;
3212         // Get destination
3213         v3s16 p3d = block->getPos();
3214         
3215         
3216 #if 0
3217         v2s16 p2d(p3d.X, p3d.Z);
3218         std::string sectordir = getSectorDir(p2d);
3219
3220         createDirs(sectordir);
3221
3222         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3223         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3224         if(o.good() == false)
3225                 throw FileNotGoodException("Cannot open block data");
3226 #endif
3227         /*
3228                 [0] u8 serialization version
3229                 [1] data
3230         */
3231         
3232         verifyDatabase();
3233         
3234         std::ostringstream o(std::ios_base::binary);
3235         
3236         o.write((char*)&version, 1);
3237         
3238         // Write basic data
3239         block->serialize(o, version);
3240         
3241         // Write extra data stored on disk
3242         block->serializeDiskExtra(o, version);
3243         
3244         // Write block to database
3245         
3246         std::string tmp = o.str();
3247         const char *bytes = tmp.c_str();
3248         
3249         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
3250                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3251         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
3252                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3253         int written = sqlite3_step(m_database_write);
3254         if(written != SQLITE_DONE)
3255                 infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3256                 <<sqlite3_errmsg(m_database)<<std::endl;
3257         // Make ready for later reuse
3258         sqlite3_reset(m_database_write);
3259         
3260         // We just wrote it to the disk so clear modified flag
3261         block->resetModified();
3262 }
3263
3264 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3265 {
3266         DSTACK(__FUNCTION_NAME);
3267
3268         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3269         try{
3270
3271                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3272                 if(is.good() == false)
3273                         throw FileNotGoodException("Cannot open block file");
3274                 
3275                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3276                 v2s16 p2d(p3d.X, p3d.Z);
3277                 
3278                 assert(sector->getPos() == p2d);
3279                 
3280                 u8 version = SER_FMT_VER_INVALID;
3281                 is.read((char*)&version, 1);
3282
3283                 if(is.fail())
3284                         throw SerializationError("ServerMap::loadBlock(): Failed"
3285                                         " to read MapBlock version");
3286
3287                 /*u32 block_size = MapBlock::serializedLength(version);
3288                 SharedBuffer<u8> data(block_size);
3289                 is.read((char*)*data, block_size);*/
3290
3291                 // This will always return a sector because we're the server
3292                 //MapSector *sector = emergeSector(p2d);
3293
3294                 MapBlock *block = NULL;
3295                 bool created_new = false;
3296                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3297                 if(block == NULL)
3298                 {
3299                         block = sector->createBlankBlockNoInsert(p3d.Y);
3300                         created_new = true;
3301                 }
3302                 
3303                 // Read basic data
3304                 block->deSerialize(is, version);
3305
3306                 // Read extra data stored on disk
3307                 block->deSerializeDiskExtra(is, version);
3308                 
3309                 // If it's a new block, insert it to the map
3310                 if(created_new)
3311                         sector->insertBlock(block);
3312                 
3313                 /*
3314                         Save blocks loaded in old format in new format
3315                 */
3316
3317                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3318                 {
3319                         saveBlock(block);
3320                         
3321                         // Should be in database now, so delete the old file
3322                         fs::RecursiveDelete(fullpath);
3323                 }
3324                 
3325                 // We just loaded it from the disk, so it's up-to-date.
3326                 block->resetModified();
3327
3328         }
3329         catch(SerializationError &e)
3330         {
3331                 infostream<<"WARNING: Invalid block data on disk "
3332                                 <<"fullpath="<<fullpath
3333                                 <<" (SerializationError). "
3334                                 <<"what()="<<e.what()
3335                                 <<std::endl;
3336                                 //" Ignoring. A new one will be generated.
3337                 assert(0);
3338
3339                 // TODO: Backup file; name is in fullpath.
3340         }
3341 }
3342
3343 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3344 {
3345         DSTACK(__FUNCTION_NAME);
3346
3347         try {
3348                 std::istringstream is(*blob, std::ios_base::binary);
3349                 
3350                 u8 version = SER_FMT_VER_INVALID;
3351                 is.read((char*)&version, 1);
3352
3353                 if(is.fail())
3354                         throw SerializationError("ServerMap::loadBlock(): Failed"
3355                                         " to read MapBlock version");
3356
3357                 /*u32 block_size = MapBlock::serializedLength(version);
3358                 SharedBuffer<u8> data(block_size);
3359                 is.read((char*)*data, block_size);*/
3360
3361                 // This will always return a sector because we're the server
3362                 //MapSector *sector = emergeSector(p2d);
3363
3364                 MapBlock *block = NULL;
3365                 bool created_new = false;
3366                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3367                 if(block == NULL)
3368                 {
3369                         block = sector->createBlankBlockNoInsert(p3d.Y);
3370                         created_new = true;
3371                 }
3372                 
3373                 // Read basic data
3374                 block->deSerialize(is, version);
3375
3376                 // Read extra data stored on disk
3377                 block->deSerializeDiskExtra(is, version);
3378                 
3379                 // If it's a new block, insert it to the map
3380                 if(created_new)
3381                         sector->insertBlock(block);
3382                 
3383                 /*
3384                         Save blocks loaded in old format in new format
3385                 */
3386
3387                 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
3388                 // Only save if asked to; no need to update version
3389                 if(save_after_load)
3390                         saveBlock(block);
3391                 
3392                 // We just loaded it from, so it's up-to-date.
3393                 block->resetModified();
3394
3395         }
3396         catch(SerializationError &e)
3397         {
3398                 infostream<<"WARNING: Invalid block data in database "
3399                                 <<" (SerializationError). "
3400                                 <<"what()="<<e.what()
3401                                 <<std::endl;
3402                                 //" Ignoring. A new one will be generated.
3403                 assert(0);
3404
3405                 // TODO: Copy to a backup database.
3406         }
3407 }
3408
3409 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3410 {
3411         DSTACK(__FUNCTION_NAME);
3412
3413         v2s16 p2d(blockpos.X, blockpos.Z);
3414
3415         if(!loadFromFolders()) {
3416                 verifyDatabase();
3417                 
3418                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3419                         infostream<<"WARNING: Could not bind block position for load: "
3420                                 <<sqlite3_errmsg(m_database)<<std::endl;
3421                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3422                         /*
3423                                 Make sure sector is loaded
3424                         */
3425                         MapSector *sector = createSector(p2d);
3426                         
3427                         /*
3428                                 Load block
3429                         */
3430                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3431                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3432                         
3433                         std::string datastr(data, len);
3434                         
3435                         loadBlock(&datastr, blockpos, sector, false);
3436
3437                         sqlite3_step(m_database_read);
3438                         // We should never get more than 1 row, so ok to reset
3439                         sqlite3_reset(m_database_read);
3440
3441                         return getBlockNoCreateNoEx(blockpos);
3442                 }
3443                 sqlite3_reset(m_database_read);
3444                 
3445                 // Not found in database, try the files
3446         }
3447
3448         // The directory layout we're going to load from.
3449         //  1 - original sectors/xxxxzzzz/
3450         //  2 - new sectors2/xxx/zzz/
3451         //  If we load from anything but the latest structure, we will
3452         //  immediately save to the new one, and remove the old.
3453         int loadlayout = 1;
3454         std::string sectordir1 = getSectorDir(p2d, 1);
3455         std::string sectordir;
3456         if(fs::PathExists(sectordir1))
3457         {
3458                 sectordir = sectordir1;
3459         }
3460         else
3461         {
3462                 loadlayout = 2;
3463                 sectordir = getSectorDir(p2d, 2);
3464         }
3465         
3466         /*
3467                 Make sure sector is loaded
3468         */
3469         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3470         if(sector == NULL)
3471         {
3472                 try{
3473                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3474                 }
3475                 catch(InvalidFilenameException &e)
3476                 {
3477                         return false;
3478                 }
3479                 catch(FileNotGoodException &e)
3480                 {
3481                         return false;
3482                 }
3483                 catch(std::exception &e)
3484                 {
3485                         return false;
3486                 }
3487         }
3488         
3489         /*
3490                 Make sure file exists
3491         */
3492
3493         std::string blockfilename = getBlockFilename(blockpos);
3494         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3495                 return NULL;
3496
3497         /*
3498                 Load block and save it to the database
3499         */
3500         loadBlock(sectordir, blockfilename, sector, true);
3501         return getBlockNoCreateNoEx(blockpos);
3502 }
3503
3504 void ServerMap::PrintInfo(std::ostream &out)
3505 {
3506         out<<"ServerMap: ";
3507 }
3508
3509 #ifndef SERVER
3510
3511 /*
3512         ClientMap
3513 */
3514
3515 ClientMap::ClientMap(
3516                 Client *client,
3517                 IGameDef *gamedef,
3518                 MapDrawControl &control,
3519                 scene::ISceneNode* parent,
3520                 scene::ISceneManager* mgr,
3521                 s32 id
3522 ):
3523         Map(dout_client, gamedef),
3524         scene::ISceneNode(parent, mgr, id),
3525         m_client(client),
3526         m_control(control),
3527         m_camera_position(0,0,0),
3528         m_camera_direction(0,0,1),
3529         m_camera_fov(PI)
3530 {
3531         m_camera_mutex.Init();
3532         assert(m_camera_mutex.IsInitialized());
3533         
3534         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3535                         BS*1000000,BS*1000000,BS*1000000);
3536 }
3537
3538 ClientMap::~ClientMap()
3539 {
3540         /*JMutexAutoLock lock(mesh_mutex);
3541         
3542         if(mesh != NULL)
3543         {
3544                 mesh->drop();
3545                 mesh = NULL;
3546         }*/
3547 }
3548
3549 MapSector * ClientMap::emergeSector(v2s16 p2d)
3550 {
3551         DSTACK(__FUNCTION_NAME);
3552         // Check that it doesn't exist already
3553         try{
3554                 return getSectorNoGenerate(p2d);
3555         }
3556         catch(InvalidPositionException &e)
3557         {
3558         }
3559         
3560         // Create a sector
3561         ClientMapSector *sector = new ClientMapSector(this, p2d, m_gamedef);
3562         
3563         {
3564                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3565                 m_sectors.insert(p2d, sector);
3566         }
3567         
3568         return sector;
3569 }
3570
3571 #if 0
3572 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3573 {
3574         DSTACK(__FUNCTION_NAME);
3575         ClientMapSector *sector = NULL;
3576
3577         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3578         
3579         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3580
3581         if(n != NULL)
3582         {
3583                 sector = (ClientMapSector*)n->getValue();
3584                 assert(sector->getId() == MAPSECTOR_CLIENT);
3585         }
3586         else
3587         {
3588                 sector = new ClientMapSector(this, p2d);
3589                 {
3590                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3591                         m_sectors.insert(p2d, sector);
3592                 }
3593         }
3594
3595         sector->deSerialize(is);
3596 }
3597 #endif
3598
3599 void ClientMap::OnRegisterSceneNode()
3600 {
3601         if(IsVisible)
3602         {
3603                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3604                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3605         }
3606
3607         ISceneNode::OnRegisterSceneNode();
3608 }
3609
3610 static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
3611                 float start_off, float end_off, u32 needed_count, INodeDefManager *nodemgr)
3612 {
3613         float d0 = (float)BS * p0.getDistanceFrom(p1);
3614         v3s16 u0 = p1 - p0;
3615         v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
3616         uf.normalize();
3617         v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
3618         u32 count = 0;
3619         for(float s=start_off; s<d0+end_off; s+=step){
3620                 v3f pf = p0f + uf * s;
3621                 v3s16 p = floatToInt(pf, BS);
3622                 MapNode n = map->getNodeNoEx(p);
3623                 bool is_transparent = false;
3624                 const ContentFeatures &f = nodemgr->get(n);
3625                 if(f.solidness == 0)
3626                         is_transparent = (f.visual_solidness != 2);
3627                 else
3628                         is_transparent = (f.solidness != 2);
3629                 if(!is_transparent){
3630                         count++;
3631                         if(count >= needed_count)
3632                                 return true;
3633                 }
3634                 step *= stepfac;
3635         }
3636         return false;
3637 }
3638
3639 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3640 {
3641         INodeDefManager *nodemgr = m_gamedef->ndef();
3642
3643         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3644         DSTACK(__FUNCTION_NAME);
3645
3646         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3647         
3648         std::string prefix;
3649         if(pass == scene::ESNRP_SOLID)
3650                 prefix = "CM: solid: ";
3651         else
3652                 prefix = "CM: transparent: ";
3653
3654         /*
3655                 This is called two times per frame, reset on the non-transparent one
3656         */
3657         if(pass == scene::ESNRP_SOLID)
3658         {
3659                 m_last_drawn_sectors.clear();
3660         }
3661
3662         /*
3663                 Get time for measuring timeout.
3664                 
3665                 Measuring time is very useful for long delays when the
3666                 machine is swapping a lot.
3667         */
3668         int time1 = time(0);
3669
3670         //u32 daynight_ratio = m_client->getDayNightRatio();
3671
3672         m_camera_mutex.Lock();
3673         v3f camera_position = m_camera_position;
3674         v3f camera_direction = m_camera_direction;
3675         f32 camera_fov = m_camera_fov;
3676         m_camera_mutex.Unlock();
3677
3678         /*
3679                 Get all blocks and draw all visible ones
3680         */
3681
3682         v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
3683         
3684         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3685
3686         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3687         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3688
3689         // Take a fair amount as we will be dropping more out later
3690         // Umm... these additions are a bit strange but they are needed.
3691         v3s16 p_blocks_min(
3692                         p_nodes_min.X / MAP_BLOCKSIZE - 3,
3693                         p_nodes_min.Y / MAP_BLOCKSIZE - 3,
3694                         p_nodes_min.Z / MAP_BLOCKSIZE - 3);
3695         v3s16 p_blocks_max(
3696                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3697                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3698                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3699         
3700         u32 vertex_count = 0;
3701         u32 meshbuffer_count = 0;
3702         
3703         // For limiting number of mesh updates per frame
3704         u32 mesh_update_count = 0;
3705         
3706         // Number of blocks in rendering range
3707         u32 blocks_in_range = 0;
3708         // Number of blocks occlusion culled
3709         u32 blocks_occlusion_culled = 0;
3710         // Number of blocks in rendering range but don't have a mesh
3711         u32 blocks_in_range_without_mesh = 0;
3712         // Blocks that had mesh that would have been drawn according to
3713         // rendering range (if max blocks limit didn't kick in)
3714         u32 blocks_would_have_drawn = 0;
3715         // Blocks that were drawn and had a mesh
3716         u32 blocks_drawn = 0;
3717         // Blocks which had a corresponding meshbuffer for this pass
3718         u32 blocks_had_pass_meshbuf = 0;
3719         // Blocks from which stuff was actually drawn
3720         u32 blocks_without_stuff = 0;
3721
3722         /*
3723                 Collect a set of blocks for drawing
3724         */
3725         
3726         core::map<v3s16, MapBlock*> drawset;
3727
3728         {
3729         ScopeProfiler sp(g_profiler, prefix+"collecting blocks for drawing", SPT_AVG);
3730
3731         for(core::map<v2s16, MapSector*>::Iterator
3732                         si = m_sectors.getIterator();
3733                         si.atEnd() == false; si++)
3734         {
3735                 MapSector *sector = si.getNode()->getValue();
3736                 v2s16 sp = sector->getPos();
3737                 
3738                 if(m_control.range_all == false)
3739                 {
3740                         if(sp.X < p_blocks_min.X
3741                         || sp.X > p_blocks_max.X
3742                         || sp.Y < p_blocks_min.Z
3743                         || sp.Y > p_blocks_max.Z)
3744                                 continue;
3745                 }
3746
3747                 core::list< MapBlock * > sectorblocks;
3748                 sector->getBlocks(sectorblocks);
3749                 
3750                 /*
3751                         Loop through blocks in sector
3752                 */
3753
3754                 u32 sector_blocks_drawn = 0;
3755                 
3756                 core::list< MapBlock * >::Iterator i;
3757                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3758                 {
3759                         MapBlock *block = *i;
3760
3761                         /*
3762                                 Compare block position to camera position, skip
3763                                 if not seen on display
3764                         */
3765                         
3766                         float range = 100000 * BS;
3767                         if(m_control.range_all == false)
3768                                 range = m_control.wanted_range * BS;
3769
3770                         float d = 0.0;
3771                         if(isBlockInSight(block->getPos(), camera_position,
3772                                         camera_direction, camera_fov,
3773                                         range, &d) == false)
3774                         {
3775                                 continue;
3776                         }
3777
3778                         // This is ugly (spherical distance limit?)
3779                         /*if(m_control.range_all == false &&
3780                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3781                                 continue;*/
3782
3783                         blocks_in_range++;
3784                         
3785 #if 1
3786                         /*
3787                                 Update expired mesh (used for day/night change)
3788
3789                                 It doesn't work exactly like it should now with the
3790                                 tasked mesh update but whatever.
3791                         */
3792
3793                         bool mesh_expired = false;
3794                         
3795                         {
3796                                 JMutexAutoLock lock(block->mesh_mutex);
3797
3798                                 mesh_expired = block->getMeshExpired();
3799
3800                                 // Mesh has not been expired and there is no mesh:
3801                                 // block has no content
3802                                 if(block->mesh == NULL && mesh_expired == false){
3803                                         blocks_in_range_without_mesh++;
3804                                         continue;
3805                                 }
3806                         }
3807
3808                         f32 faraway = BS*50;
3809                         //f32 faraway = m_control.wanted_range * BS;
3810                         
3811                         /*
3812                                 This has to be done with the mesh_mutex unlocked
3813                         */
3814                         // Pretty random but this should work somewhat nicely
3815                         if(mesh_expired && (
3816                                         (mesh_update_count < 3
3817                                                 && (d < faraway || mesh_update_count < 2)
3818                                         )
3819                                         || 
3820                                         (m_control.range_all && mesh_update_count < 20)
3821                                 )
3822                         )
3823                         /*if(mesh_expired && mesh_update_count < 6
3824                                         && (d < faraway || mesh_update_count < 3))*/
3825                         {
3826                                 mesh_update_count++;
3827
3828                                 // Mesh has been expired: generate new mesh
3829                                 //block->updateMesh(daynight_ratio);
3830                                 m_client->addUpdateMeshTask(block->getPos());
3831
3832                                 mesh_expired = false;
3833                         }
3834 #endif
3835
3836                         /*
3837                                 Occlusion culling
3838                         */
3839
3840                         v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
3841                         cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);
3842                         float step = BS*1;
3843                         float stepfac = 1.1;
3844                         float startoff = BS*1;
3845                         float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42;
3846                         v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
3847                         s16 bs2 = MAP_BLOCKSIZE/2 + 1;
3848                         u32 needed_count = 1;
3849                         if(
3850                                 isOccluded(this, spn, cpn + v3s16(0,0,0),
3851                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3852                                 isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
3853                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3854                                 isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
3855                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3856                                 isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
3857                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3858                                 isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
3859                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3860                                 isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
3861                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3862                                 isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
3863                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3864                                 isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
3865                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3866                                 isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
3867                                         step, stepfac, startoff, endoff, needed_count, nodemgr)
3868                         )
3869                         {
3870                                 blocks_occlusion_culled++;
3871                                 continue;
3872                         }
3873                         
3874                         // This block is in range. Reset usage timer.
3875                         block->resetUsageTimer();
3876
3877                         /*
3878                                 Ignore if mesh doesn't exist
3879                         */
3880                         {
3881                                 JMutexAutoLock lock(block->mesh_mutex);
3882
3883                                 scene::SMesh *mesh = block->mesh;
3884                                 
3885                                 if(mesh == NULL){
3886                                         blocks_in_range_without_mesh++;
3887                                         continue;
3888                                 }
3889                         }
3890                         
3891                         // Limit block count in case of a sudden increase
3892                         blocks_would_have_drawn++;
3893                         if(blocks_drawn >= m_control.wanted_max_blocks
3894                                         && m_control.range_all == false
3895                                         && d > m_control.wanted_min_range * BS)
3896                                 continue;
3897                         
3898                         // Add to set
3899                         drawset[block->getPos()] = block;
3900                         
3901                         sector_blocks_drawn++;
3902                         blocks_drawn++;
3903
3904                 } // foreach sectorblocks
3905
3906                 if(sector_blocks_drawn != 0)
3907                         m_last_drawn_sectors[sp] = true;
3908         }
3909         } // ScopeProfiler
3910         
3911         /*
3912                 Draw the selected MapBlocks
3913         */
3914
3915         {
3916         ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
3917
3918         int timecheck_counter = 0;
3919         for(core::map<v3s16, MapBlock*>::Iterator
3920                         i = drawset.getIterator();
3921                         i.atEnd() == false; i++)
3922         {
3923                 {
3924                         timecheck_counter++;
3925                         if(timecheck_counter > 50)
3926                         {
3927                                 timecheck_counter = 0;
3928                                 int time2 = time(0);
3929                                 if(time2 > time1 + 4)
3930                                 {
3931                                         infostream<<"ClientMap::renderMap(): "
3932                                                 "Rendering takes ages, returning."
3933                                                 <<std::endl;
3934                                         return;
3935                                 }
3936                         }
3937                 }
3938                 
3939                 MapBlock *block = i.getNode()->getValue();
3940
3941                 /*
3942                         Draw the faces of the block
3943                 */
3944                 {
3945                         JMutexAutoLock lock(block->mesh_mutex);
3946
3947                         scene::SMesh *mesh = block->mesh;
3948                         assert(mesh);
3949                         
3950                         u32 c = mesh->getMeshBufferCount();
3951                         bool stuff_actually_drawn = false;
3952                         for(u32 i=0; i<c; i++)
3953                         {
3954                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3955                                 const video::SMaterial& material = buf->getMaterial();
3956                                 video::IMaterialRenderer* rnd =
3957                                                 driver->getMaterialRenderer(material.MaterialType);
3958                                 bool transparent = (rnd && rnd->isTransparent());
3959                                 // Render transparent on transparent pass and likewise.
3960                                 if(transparent == is_transparent_pass)
3961                                 {
3962                                         if(buf->getVertexCount() == 0)
3963                                                 errorstream<<"Block ["<<analyze_block(block)
3964                                                                 <<"] contains an empty meshbuf"<<std::endl;
3965                                         /*
3966                                                 This *shouldn't* hurt too much because Irrlicht
3967                                                 doesn't change opengl textures if the old
3968                                                 material has the same texture.
3969                                         */
3970                                         driver->setMaterial(buf->getMaterial());
3971                                         driver->drawMeshBuffer(buf);
3972                                         vertex_count += buf->getVertexCount();
3973                                         meshbuffer_count++;
3974                                         stuff_actually_drawn = true;
3975                                 }
3976                         }
3977                         if(stuff_actually_drawn)
3978                                 blocks_had_pass_meshbuf++;
3979                         else
3980                                 blocks_without_stuff++;
3981                 }
3982         }
3983         } // ScopeProfiler
3984         
3985         // Log only on solid pass because values are the same
3986         if(pass == scene::ESNRP_SOLID){
3987                 g_profiler->avg("CM: blocks in range", blocks_in_range);
3988                 g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
3989                 if(blocks_in_range != 0)
3990                         g_profiler->avg("CM: blocks in range without mesh (frac)",
3991                                         (float)blocks_in_range_without_mesh/blocks_in_range);
3992                 g_profiler->avg("CM: blocks drawn", blocks_drawn);
3993         }
3994         
3995         g_profiler->avg(prefix+"vertices drawn", vertex_count);
3996         if(blocks_had_pass_meshbuf != 0)
3997                 g_profiler->avg(prefix+"meshbuffers per block",
3998                                 (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
3999         if(blocks_drawn != 0)
4000                 g_profiler->avg(prefix+"empty blocks (frac)",
4001                                 (float)blocks_without_stuff / blocks_drawn);
4002
4003         m_control.blocks_drawn = blocks_drawn;
4004         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
4005
4006         /*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
4007                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
4008 }
4009
4010 void ClientMap::renderPostFx()
4011 {
4012         INodeDefManager *nodemgr = m_gamedef->ndef();
4013
4014         // Sadly ISceneManager has no "post effects" render pass, in that case we
4015         // could just register for that and handle it in renderMap().
4016
4017         m_camera_mutex.Lock();
4018         v3f camera_position = m_camera_position;
4019         m_camera_mutex.Unlock();
4020
4021         MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
4022
4023         // - If the player is in a solid node, make everything black.
4024         // - If the player is in liquid, draw a semi-transparent overlay.
4025         const ContentFeatures& features = nodemgr->get(n);
4026         video::SColor post_effect_color = features.post_effect_color;
4027         if(features.solidness == 2 && g_settings->getBool("free_move") == false)
4028         {
4029                 post_effect_color = video::SColor(255, 0, 0, 0);
4030         }
4031         if (post_effect_color.getAlpha() != 0)
4032         {
4033                 // Draw a full-screen rectangle
4034                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
4035                 v2u32 ss = driver->getScreenSize();
4036                 core::rect<s32> rect(0,0, ss.X, ss.Y);
4037                 driver->draw2DRectangle(post_effect_color, rect);
4038         }
4039 }
4040
4041 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
4042                 core::map<v3s16, MapBlock*> *affected_blocks)
4043 {
4044         bool changed = false;
4045         /*
4046                 Add it to all blocks touching it
4047         */
4048         v3s16 dirs[7] = {
4049                 v3s16(0,0,0), // this
4050                 v3s16(0,0,1), // back
4051                 v3s16(0,1,0), // top
4052                 v3s16(1,0,0), // right
4053                 v3s16(0,0,-1), // front
4054                 v3s16(0,-1,0), // bottom
4055                 v3s16(-1,0,0), // left
4056         };
4057         for(u16 i=0; i<7; i++)
4058         {
4059                 v3s16 p2 = p + dirs[i];
4060                 // Block position of neighbor (or requested) node
4061                 v3s16 blockpos = getNodeBlockPos(p2);
4062                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4063                 if(blockref == NULL)
4064                         continue;
4065                 // Relative position of requested node
4066                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4067                 if(blockref->setTempMod(relpos, mod))
4068                 {
4069                         changed = true;
4070                 }
4071         }
4072         if(changed && affected_blocks!=NULL)
4073         {
4074                 for(u16 i=0; i<7; i++)
4075                 {
4076                         v3s16 p2 = p + dirs[i];
4077                         // Block position of neighbor (or requested) node
4078                         v3s16 blockpos = getNodeBlockPos(p2);
4079                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4080                         if(blockref == NULL)
4081                                 continue;
4082                         affected_blocks->insert(blockpos, blockref);
4083                 }
4084         }
4085         return changed;
4086 }
4087
4088 bool ClientMap::clearTempMod(v3s16 p,
4089                 core::map<v3s16, MapBlock*> *affected_blocks)
4090 {
4091         bool changed = false;
4092         v3s16 dirs[7] = {
4093                 v3s16(0,0,0), // this
4094                 v3s16(0,0,1), // back
4095                 v3s16(0,1,0), // top
4096                 v3s16(1,0,0), // right
4097                 v3s16(0,0,-1), // front
4098                 v3s16(0,-1,0), // bottom
4099                 v3s16(-1,0,0), // left
4100         };
4101         for(u16 i=0; i<7; i++)
4102         {
4103                 v3s16 p2 = p + dirs[i];
4104                 // Block position of neighbor (or requested) node
4105                 v3s16 blockpos = getNodeBlockPos(p2);
4106                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4107                 if(blockref == NULL)
4108                         continue;
4109                 // Relative position of requested node
4110                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4111                 if(blockref->clearTempMod(relpos))
4112                 {
4113                         changed = true;
4114                 }
4115         }
4116         if(changed && affected_blocks!=NULL)
4117         {
4118                 for(u16 i=0; i<7; i++)
4119                 {
4120                         v3s16 p2 = p + dirs[i];
4121                         // Block position of neighbor (or requested) node
4122                         v3s16 blockpos = getNodeBlockPos(p2);
4123                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4124                         if(blockref == NULL)
4125                                 continue;
4126                         affected_blocks->insert(blockpos, blockref);
4127                 }
4128         }
4129         return changed;
4130 }
4131
4132 void ClientMap::expireMeshes(bool only_daynight_diffed)
4133 {
4134         TimeTaker timer("expireMeshes()");
4135
4136         core::map<v2s16, MapSector*>::Iterator si;
4137         si = m_sectors.getIterator();
4138         for(; si.atEnd() == false; si++)
4139         {
4140                 MapSector *sector = si.getNode()->getValue();
4141
4142                 core::list< MapBlock * > sectorblocks;
4143                 sector->getBlocks(sectorblocks);
4144                 
4145                 core::list< MapBlock * >::Iterator i;
4146                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
4147                 {
4148                         MapBlock *block = *i;
4149
4150                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
4151                         {
4152                                 continue;
4153                         }
4154                         
4155                         {
4156                                 JMutexAutoLock lock(block->mesh_mutex);
4157                                 if(block->mesh != NULL)
4158                                 {
4159                                         /*block->mesh->drop();
4160                                         block->mesh = NULL;*/
4161                                         block->setMeshExpired(true);
4162                                 }
4163                         }
4164                 }
4165         }
4166 }
4167
4168 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
4169 {
4170         assert(mapType() == MAPTYPE_CLIENT);
4171
4172         try{
4173                 v3s16 p = blockpos + v3s16(0,0,0);
4174                 MapBlock *b = getBlockNoCreate(p);
4175                 b->updateMesh(daynight_ratio);
4176                 //b->setMeshExpired(true);
4177         }
4178         catch(InvalidPositionException &e){}
4179         // Leading edge
4180         try{
4181                 v3s16 p = blockpos + v3s16(-1,0,0);
4182                 MapBlock *b = getBlockNoCreate(p);
4183                 b->updateMesh(daynight_ratio);
4184                 //b->setMeshExpired(true);
4185         }
4186         catch(InvalidPositionException &e){}
4187         try{
4188                 v3s16 p = blockpos + v3s16(0,-1,0);
4189                 MapBlock *b = getBlockNoCreate(p);
4190                 b->updateMesh(daynight_ratio);
4191                 //b->setMeshExpired(true);
4192         }
4193         catch(InvalidPositionException &e){}
4194         try{
4195                 v3s16 p = blockpos + v3s16(0,0,-1);
4196                 MapBlock *b = getBlockNoCreate(p);
4197                 b->updateMesh(daynight_ratio);
4198                 //b->setMeshExpired(true);
4199         }
4200         catch(InvalidPositionException &e){}
4201 }
4202
4203 #if 0
4204 /*
4205         Update mesh of block in which the node is, and if the node is at the
4206         leading edge, update the appropriate leading blocks too.
4207 */
4208 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
4209 {
4210         v3s16 dirs[4] = {
4211                 v3s16(0,0,0),
4212                 v3s16(-1,0,0),
4213                 v3s16(0,-1,0),
4214                 v3s16(0,0,-1),
4215         };
4216         v3s16 blockposes[4];
4217         for(u32 i=0; i<4; i++)
4218         {
4219                 v3s16 np = nodepos + dirs[i];
4220                 blockposes[i] = getNodeBlockPos(np);
4221                 // Don't update mesh of block if it has been done already
4222                 bool already_updated = false;
4223                 for(u32 j=0; j<i; j++)
4224                 {
4225                         if(blockposes[j] == blockposes[i])
4226                         {
4227                                 already_updated = true;
4228                                 break;
4229                         }
4230                 }
4231                 if(already_updated)
4232                         continue;
4233                 // Update mesh
4234                 MapBlock *b = getBlockNoCreate(blockposes[i]);
4235                 b->updateMesh(daynight_ratio);
4236         }
4237 }
4238 #endif
4239
4240 void ClientMap::PrintInfo(std::ostream &out)
4241 {
4242         out<<"ClientMap: ";
4243 }
4244
4245 #endif // !SERVER
4246
4247 /*
4248         MapVoxelManipulator
4249 */
4250
4251 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4252 {
4253         m_map = map;
4254 }
4255
4256 MapVoxelManipulator::~MapVoxelManipulator()
4257 {
4258         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4259                         <<std::endl;*/
4260 }
4261
4262 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4263 {
4264         TimeTaker timer1("emerge", &emerge_time);
4265
4266         // Units of these are MapBlocks
4267         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4268         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4269
4270         VoxelArea block_area_nodes
4271                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4272
4273         addArea(block_area_nodes);
4274
4275         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4276         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4277         for(s32 x=p_min.X; x<=p_max.X; x++)
4278         {
4279                 v3s16 p(x,y,z);
4280                 core::map<v3s16, bool>::Node *n;
4281                 n = m_loaded_blocks.find(p);
4282                 if(n != NULL)
4283                         continue;
4284                 
4285                 bool block_data_inexistent = false;
4286                 try
4287                 {
4288                         TimeTaker timer1("emerge load", &emerge_load_time);
4289
4290                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4291                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4292                                         <<" wanted area: ";
4293                         a.print(infostream);
4294                         infostream<<std::endl;*/
4295                         
4296                         MapBlock *block = m_map->getBlockNoCreate(p);
4297                         if(block->isDummy())
4298                                 block_data_inexistent = true;
4299                         else
4300                                 block->copyTo(*this);
4301                 }
4302                 catch(InvalidPositionException &e)
4303                 {
4304                         block_data_inexistent = true;
4305                 }
4306
4307                 if(block_data_inexistent)
4308                 {
4309                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4310                         // Fill with VOXELFLAG_INEXISTENT
4311                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4312                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4313                         {
4314                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4315                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4316                         }
4317                 }
4318
4319                 m_loaded_blocks.insert(p, !block_data_inexistent);
4320         }
4321
4322         //infostream<<"emerge done"<<std::endl;
4323 }
4324
4325 /*
4326         SUGG: Add an option to only update eg. water and air nodes.
4327               This will make it interfere less with important stuff if
4328                   run on background.
4329 */
4330 void MapVoxelManipulator::blitBack
4331                 (core::map<v3s16, MapBlock*> & modified_blocks)
4332 {
4333         if(m_area.getExtent() == v3s16(0,0,0))
4334                 return;
4335         
4336         //TimeTaker timer1("blitBack");
4337
4338         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4339                         <<m_loaded_blocks.size()<<std::endl;*/
4340         
4341         /*
4342                 Initialize block cache
4343         */
4344         v3s16 blockpos_last;
4345         MapBlock *block = NULL;
4346         bool block_checked_in_modified = false;
4347
4348         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4349         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4350         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4351         {
4352                 v3s16 p(x,y,z);
4353
4354                 u8 f = m_flags[m_area.index(p)];
4355                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4356                         continue;
4357
4358                 MapNode &n = m_data[m_area.index(p)];
4359                         
4360                 v3s16 blockpos = getNodeBlockPos(p);
4361                 
4362                 try
4363                 {
4364                         // Get block
4365                         if(block == NULL || blockpos != blockpos_last){
4366                                 block = m_map->getBlockNoCreate(blockpos);
4367                                 blockpos_last = blockpos;
4368                                 block_checked_in_modified = false;
4369                         }
4370                         
4371                         // Calculate relative position in block
4372                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4373
4374                         // Don't continue if nothing has changed here
4375                         if(block->getNode(relpos) == n)
4376                                 continue;
4377
4378                         //m_map->setNode(m_area.MinEdge + p, n);
4379                         block->setNode(relpos, n);
4380                         
4381                         /*
4382                                 Make sure block is in modified_blocks
4383                         */
4384                         if(block_checked_in_modified == false)
4385                         {
4386                                 modified_blocks[blockpos] = block;
4387                                 block_checked_in_modified = true;
4388                         }
4389                 }
4390                 catch(InvalidPositionException &e)
4391                 {
4392                 }
4393         }
4394 }
4395
4396 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4397                 MapVoxelManipulator(map),
4398                 m_create_area(false)
4399 {
4400 }
4401
4402 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4403 {
4404 }
4405
4406 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4407 {
4408         // Just create the area so that it can be pointed to
4409         VoxelManipulator::emerge(a, caller_id);
4410 }
4411
4412 void ManualMapVoxelManipulator::initialEmerge(
4413                 v3s16 blockpos_min, v3s16 blockpos_max)
4414 {
4415         TimeTaker timer1("initialEmerge", &emerge_time);
4416
4417         // Units of these are MapBlocks
4418         v3s16 p_min = blockpos_min;
4419         v3s16 p_max = blockpos_max;
4420
4421         VoxelArea block_area_nodes
4422                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4423         
4424         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4425         if(size_MB >= 1)
4426         {
4427                 infostream<<"initialEmerge: area: ";
4428                 block_area_nodes.print(infostream);
4429                 infostream<<" ("<<size_MB<<"MB)";
4430                 infostream<<std::endl;
4431         }
4432
4433         addArea(block_area_nodes);
4434
4435         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4436         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4437         for(s32 x=p_min.X; x<=p_max.X; x++)
4438         {
4439                 v3s16 p(x,y,z);
4440                 core::map<v3s16, bool>::Node *n;
4441                 n = m_loaded_blocks.find(p);
4442                 if(n != NULL)
4443                         continue;
4444                 
4445                 bool block_data_inexistent = false;
4446                 try
4447                 {
4448                         TimeTaker timer1("emerge load", &emerge_load_time);
4449
4450                         MapBlock *block = m_map->getBlockNoCreate(p);
4451                         if(block->isDummy())
4452                                 block_data_inexistent = true;
4453                         else
4454                                 block->copyTo(*this);
4455                 }
4456                 catch(InvalidPositionException &e)
4457                 {
4458                         block_data_inexistent = true;
4459                 }
4460
4461                 if(block_data_inexistent)
4462                 {
4463                         /*
4464                                 Mark area inexistent
4465                         */
4466                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4467                         // Fill with VOXELFLAG_INEXISTENT
4468                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4469                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4470                         {
4471                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4472                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4473                         }
4474                 }
4475
4476                 m_loaded_blocks.insert(p, !block_data_inexistent);
4477         }
4478 }
4479
4480 void ManualMapVoxelManipulator::blitBackAll(
4481                 core::map<v3s16, MapBlock*> * modified_blocks)
4482 {
4483         if(m_area.getExtent() == v3s16(0,0,0))
4484                 return;
4485         
4486         /*
4487                 Copy data of all blocks
4488         */
4489         for(core::map<v3s16, bool>::Iterator
4490                         i = m_loaded_blocks.getIterator();
4491                         i.atEnd() == false; i++)
4492         {
4493                 v3s16 p = i.getNode()->getKey();
4494                 bool existed = i.getNode()->getValue();
4495                 if(existed == false)
4496                 {
4497                         // The Great Bug was found using this
4498                         /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
4499                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4500                                         <<std::endl;*/
4501                         continue;
4502                 }
4503                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4504                 if(block == NULL)
4505                 {
4506                         infostream<<"WARNING: "<<__FUNCTION_NAME
4507                                         <<": got NULL block "
4508                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4509                                         <<std::endl;
4510                         continue;
4511                 }
4512
4513                 block->copyFrom(*this);
4514
4515                 if(modified_blocks)
4516                         modified_blocks->insert(p, block);
4517         }
4518 }
4519
4520 //END