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