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