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