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