423a07dcdc61394b4600aa136af40bcfe2c6a757
[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         beginSave();
1412         si = m_sectors.getIterator();
1413         for(; si.atEnd() == false; si++)
1414         {
1415                 MapSector *sector = si.getNode()->getValue();
1416
1417                 bool all_blocks_deleted = true;
1418
1419                 core::list<MapBlock*> blocks;
1420                 sector->getBlocks(blocks);
1421                 
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
1455                 if(all_blocks_deleted)
1456                 {
1457                         sector_deletion_queue.push_back(si.getNode()->getKey());
1458                 }
1459         }
1460         endSave();
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         if (g_settings.get("fixed_map_seed").empty())
1898         {
1899                 m_seed = (((u64)(myrand()%0xffff)<<0)
1900                                 + ((u64)(myrand()%0xffff)<<16)
1901                                 + ((u64)(myrand()%0xffff)<<32)
1902                                 + ((u64)(myrand()%0xffff)<<48));
1903         }
1904         else
1905         {
1906                 m_seed = g_settings.getU64("fixed_map_seed");
1907         }
1908
1909         /*
1910                 Experimental and debug stuff
1911         */
1912
1913         {
1914         }
1915
1916         /*
1917                 Try to load map; if not found, create a new one.
1918         */
1919
1920         m_savedir = savedir;
1921         m_map_saving_enabled = false;
1922
1923         try
1924         {
1925                 // If directory exists, check contents and load if possible
1926                 if(fs::PathExists(m_savedir))
1927                 {
1928                         // If directory is empty, it is safe to save into it.
1929                         if(fs::GetDirListing(m_savedir).size() == 0)
1930                         {
1931                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1932                                                 <<std::endl;
1933                                 m_map_saving_enabled = true;
1934                         }
1935                         else
1936                         {
1937                                 try{
1938                                         // Load map metadata (seed, chunksize)
1939                                         loadMapMeta();
1940                                 }
1941                                 catch(FileNotGoodException &e){
1942                                         dstream<<DTIME<<"WARNING: Could not load map metadata"
1943                                                         //<<" Disabling chunk-based generator."
1944                                                         <<std::endl;
1945                                         //m_chunksize = 0;
1946                                 }
1947
1948                                 /*try{
1949                                         // Load chunk metadata
1950                                         loadChunkMeta();
1951                                 }
1952                                 catch(FileNotGoodException &e){
1953                                         dstream<<DTIME<<"WARNING: Could not load chunk metadata."
1954                                                         <<" Disabling chunk-based generator."
1955                                                         <<std::endl;
1956                                         m_chunksize = 0;
1957                                 }*/
1958
1959                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1960                                                 "metadata and sector (0,0) from "<<savedir<<
1961                                                 ", assuming valid save directory."
1962                                                 <<std::endl;*/
1963
1964                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1965                                                 <<"and chunk metadata from "<<savedir
1966                                                 <<", assuming valid save directory."
1967                                                 <<std::endl;
1968
1969                                 m_map_saving_enabled = true;
1970                                 // Map loaded, not creating new one
1971                                 return;
1972                         }
1973                 }
1974                 // If directory doesn't exist, it is safe to save to it
1975                 else{
1976                         m_map_saving_enabled = true;
1977                 }
1978         }
1979         catch(std::exception &e)
1980         {
1981                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1982                                 <<", exception: "<<e.what()<<std::endl;
1983                 dstream<<"Please remove the map or fix it."<<std::endl;
1984                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1985         }
1986
1987         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1988
1989         // Create zero sector
1990         emergeSector(v2s16(0,0));
1991
1992         // Initially write whole map
1993         save(false);
1994 }
1995
1996 ServerMap::~ServerMap()
1997 {
1998         dstream<<__FUNCTION_NAME<<std::endl;
1999
2000         try
2001         {
2002                 if(m_map_saving_enabled)
2003                 {
2004                         // Save only changed parts
2005                         save(true);
2006                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
2007                 }
2008                 else
2009                 {
2010                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
2011                 }
2012         }
2013         catch(std::exception &e)
2014         {
2015                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
2016                                 <<", exception: "<<e.what()<<std::endl;
2017         }
2018
2019         /*
2020                 Close database if it was opened
2021         */
2022         if(m_database_read)
2023                 sqlite3_finalize(m_database_read);
2024         if(m_database_write)
2025                 sqlite3_finalize(m_database_write);
2026         if(m_database)
2027                 sqlite3_close(m_database);
2028
2029 #if 0
2030         /*
2031                 Free all MapChunks
2032         */
2033         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2034         for(; i.atEnd() == false; i++)
2035         {
2036                 MapChunk *chunk = i.getNode()->getValue();
2037                 delete chunk;
2038         }
2039 #endif
2040 }
2041
2042 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2043 {
2044         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2045         if(enable_mapgen_debug_info)
2046                 dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2047                                 <<blockpos.Z<<")"<<std::endl;
2048         
2049         // Do nothing if not inside limits (+-1 because of neighbors)
2050         if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
2051                 blockpos_over_limit(blockpos + v3s16(1,1,1)))
2052         {
2053                 data->no_op = true;
2054                 return;
2055         }
2056         
2057         data->no_op = false;
2058         data->seed = m_seed;
2059         data->blockpos = blockpos;
2060
2061         /*
2062                 Create the whole area of this and the neighboring blocks
2063         */
2064         {
2065                 //TimeTaker timer("initBlockMake() create area");
2066                 
2067                 for(s16 x=-1; x<=1; x++)
2068                 for(s16 z=-1; z<=1; z++)
2069                 {
2070                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2071                         // Sector metadata is loaded from disk if not already loaded.
2072                         ServerMapSector *sector = createSector(sectorpos);
2073                         assert(sector);
2074
2075                         for(s16 y=-1; y<=1; y++)
2076                         {
2077                                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2078                                 //MapBlock *block = createBlock(p);
2079                                 // 1) get from memory, 2) load from disk
2080                                 MapBlock *block = emergeBlock(p, false);
2081                                 // 3) create a blank one
2082                                 if(block == NULL)
2083                                 {
2084                                         block = createBlock(p);
2085
2086                                         /*
2087                                                 Block gets sunlight if this is true.
2088
2089                                                 Refer to the map generator heuristics.
2090                                         */
2091                                         bool ug = mapgen::block_is_underground(data->seed, p);
2092                                         block->setIsUnderground(ug);
2093                                 }
2094
2095                                 // Lighting will not be valid after make_chunk is called
2096                                 block->setLightingExpired(true);
2097                                 // Lighting will be calculated
2098                                 //block->setLightingExpired(false);
2099                         }
2100                 }
2101         }
2102         
2103         /*
2104                 Now we have a big empty area.
2105
2106                 Make a ManualMapVoxelManipulator that contains this and the
2107                 neighboring blocks
2108         */
2109         
2110         // The area that contains this block and it's neighbors
2111         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2112         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2113         
2114         data->vmanip = new ManualMapVoxelManipulator(this);
2115         //data->vmanip->setMap(this);
2116
2117         // Add the area
2118         {
2119                 //TimeTaker timer("initBlockMake() initialEmerge");
2120                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2121         }
2122
2123         // Data is ready now.
2124 }
2125
2126 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2127                 core::map<v3s16, MapBlock*> &changed_blocks)
2128 {
2129         v3s16 blockpos = data->blockpos;
2130         /*dstream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2131                         <<blockpos.Z<<")"<<std::endl;*/
2132
2133         if(data->no_op)
2134         {
2135                 //dstream<<"finishBlockMake(): no-op"<<std::endl;
2136                 return NULL;
2137         }
2138
2139         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2140
2141         /*dstream<<"Resulting vmanip:"<<std::endl;
2142         data->vmanip.print(dstream);*/
2143         
2144         /*
2145                 Blit generated stuff to map
2146                 NOTE: blitBackAll adds nearly everything to changed_blocks
2147         */
2148         {
2149                 // 70ms @cs=8
2150                 //TimeTaker timer("finishBlockMake() blitBackAll");
2151                 data->vmanip->blitBackAll(&changed_blocks);
2152         }
2153
2154         if(enable_mapgen_debug_info)
2155                 dstream<<"finishBlockMake: changed_blocks.size()="
2156                                 <<changed_blocks.size()<<std::endl;
2157
2158         /*
2159                 Copy transforming liquid information
2160         */
2161         while(data->transforming_liquid.size() > 0)
2162         {
2163                 v3s16 p = data->transforming_liquid.pop_front();
2164                 m_transforming_liquid.push_back(p);
2165         }
2166         
2167         /*
2168                 Get central block
2169         */
2170         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2171         assert(block);
2172
2173         /*
2174                 Set is_underground flag for lighting with sunlight.
2175
2176                 Refer to map generator heuristics.
2177
2178                 NOTE: This is done in initChunkMake
2179         */
2180         //block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2181
2182
2183         /*
2184                 Add sunlight to central block.
2185                 This makes in-dark-spawning monsters to not flood the whole thing.
2186                 Do not spread the light, though.
2187         */
2188         /*core::map<v3s16, bool> light_sources;
2189         bool black_air_left = false;
2190         block->propagateSunlight(light_sources, true, &black_air_left);*/
2191
2192         /*
2193                 NOTE: Lighting and object adding shouldn't really be here, but
2194                 lighting is a bit tricky to move properly to makeBlock.
2195                 TODO: Do this the right way anyway, that is, move it to makeBlock.
2196                       - There needs to be some way for makeBlock to report back if
2197                             the lighting update is going further down because of the
2198                                 new block blocking light
2199         */
2200
2201         /*
2202                 Update lighting
2203                 NOTE: This takes ~60ms, TODO: Investigate why
2204         */
2205         {
2206                 TimeTaker t("finishBlockMake lighting update");
2207
2208                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2209 #if 1
2210                 // Center block
2211                 lighting_update_blocks.insert(block->getPos(), block);
2212
2213                 /*{
2214                         s16 x = 0;
2215                         s16 z = 0;
2216                         v3s16 p = block->getPos()+v3s16(x,1,z);
2217                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2218                 }*/
2219 #endif
2220 #if 0
2221                 // All modified blocks
2222                 // NOTE: Should this be done? If this is not done, then the lighting
2223                 // of the others will be updated in a different place, one by one, i
2224                 // think... or they might not? Well, at least they are left marked as
2225                 // "lighting expired"; it seems that is not handled at all anywhere,
2226                 // so enabling this will slow it down A LOT because otherwise it
2227                 // would not do this at all. This causes the black trees.
2228                 for(core::map<v3s16, MapBlock*>::Iterator
2229                                 i = changed_blocks.getIterator();
2230                                 i.atEnd() == false; i++)
2231                 {
2232                         lighting_update_blocks.insert(i.getNode()->getKey(),
2233                                         i.getNode()->getValue());
2234                 }
2235                 /*// Also force-add all the upmost blocks for proper sunlight
2236                 for(s16 x=-1; x<=1; x++)
2237                 for(s16 z=-1; z<=1; z++)
2238                 {
2239                         v3s16 p = block->getPos()+v3s16(x,1,z);
2240                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2241                 }*/
2242 #endif
2243                 updateLighting(lighting_update_blocks, changed_blocks);
2244                 
2245                 /*
2246                         Set lighting to non-expired state in all of them.
2247                         This is cheating, but it is not fast enough if all of them
2248                         would actually be updated.
2249                 */
2250                 for(s16 x=-1; x<=1; x++)
2251                 for(s16 y=-1; y<=1; y++)
2252                 for(s16 z=-1; z<=1; z++)
2253                 {
2254                         v3s16 p = block->getPos()+v3s16(x,y,z);
2255                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2256                 }
2257
2258                 if(enable_mapgen_debug_info == false)
2259                         t.stop(true); // Hide output
2260         }
2261
2262         /*
2263                 Add random objects to block
2264         */
2265         mapgen::add_random_objects(block);
2266
2267         /*
2268                 Go through changed blocks
2269         */
2270         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2271                         i.atEnd() == false; i++)
2272         {
2273                 MapBlock *block = i.getNode()->getValue();
2274                 assert(block);
2275                 /*
2276                         Update day/night difference cache of the MapBlocks
2277                 */
2278                 block->updateDayNightDiff();
2279                 /*
2280                         Set block as modified
2281                 */
2282                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2283         }
2284
2285         /*
2286                 Set central block as generated
2287         */
2288         block->setGenerated(true);
2289         
2290         /*
2291                 Save changed parts of map
2292                 NOTE: Will be saved later.
2293         */
2294         //save(true);
2295
2296         /*dstream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2297                         <<blockpos.Z<<")"<<std::endl;*/
2298 #if 0
2299         if(enable_mapgen_debug_info)
2300         {
2301                 /*
2302                         Analyze resulting blocks
2303                 */
2304                 for(s16 x=-1; x<=1; x++)
2305                 for(s16 y=-1; y<=1; y++)
2306                 for(s16 z=-1; z<=1; z++)
2307                 {
2308                         v3s16 p = block->getPos()+v3s16(x,y,z);
2309                         MapBlock *block = getBlockNoCreateNoEx(p);
2310                         char spos[20];
2311                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2312                         dstream<<"Generated "<<spos<<": "
2313                                         <<analyze_block(block)<<std::endl;
2314                 }
2315         }
2316 #endif
2317
2318         return block;
2319 }
2320
2321 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2322 {
2323         DSTACKF("%s: p2d=(%d,%d)",
2324                         __FUNCTION_NAME,
2325                         p2d.X, p2d.Y);
2326         
2327         /*
2328                 Check if it exists already in memory
2329         */
2330         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2331         if(sector != NULL)
2332                 return sector;
2333         
2334         /*
2335                 Try to load it from disk (with blocks)
2336         */
2337         //if(loadSectorFull(p2d) == true)
2338
2339         /*
2340                 Try to load metadata from disk
2341         */
2342 #if 0
2343         if(loadSectorMeta(p2d) == true)
2344         {
2345                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2346                 if(sector == NULL)
2347                 {
2348                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2349                         throw InvalidPositionException("");
2350                 }
2351                 return sector;
2352         }
2353 #endif
2354         /*
2355                 Do not create over-limit
2356         */
2357         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2358         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2359         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2360         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2361                 throw InvalidPositionException("createSector(): pos. over limit");
2362
2363         /*
2364                 Generate blank sector
2365         */
2366         
2367         sector = new ServerMapSector(this, p2d);
2368         
2369         // Sector position on map in nodes
2370         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2371
2372         /*
2373                 Insert to container
2374         */
2375         m_sectors.insert(p2d, sector);
2376         
2377         return sector;
2378 }
2379
2380 /*
2381         This is a quick-hand function for calling makeBlock().
2382 */
2383 MapBlock * ServerMap::generateBlock(
2384                 v3s16 p,
2385                 core::map<v3s16, MapBlock*> &modified_blocks
2386 )
2387 {
2388         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2389         
2390         /*dstream<<"generateBlock(): "
2391                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2392                         <<std::endl;*/
2393         
2394         bool enable_mapgen_debug_info = g_settings.getBool("enable_mapgen_debug_info");
2395
2396         TimeTaker timer("generateBlock");
2397         
2398         //MapBlock *block = original_dummy;
2399                         
2400         v2s16 p2d(p.X, p.Z);
2401         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2402         
2403         /*
2404                 Do not generate over-limit
2405         */
2406         if(blockpos_over_limit(p))
2407         {
2408                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2409                 throw InvalidPositionException("generateBlock(): pos. over limit");
2410         }
2411
2412         /*
2413                 Create block make data
2414         */
2415         mapgen::BlockMakeData data;
2416         initBlockMake(&data, p);
2417
2418         /*
2419                 Generate block
2420         */
2421         {
2422                 TimeTaker t("mapgen::make_block()");
2423                 mapgen::make_block(&data);
2424
2425                 if(enable_mapgen_debug_info == false)
2426                         t.stop(true); // Hide output
2427         }
2428
2429         /*
2430                 Blit data back on map, update lighting, add mobs and whatever this does
2431         */
2432         finishBlockMake(&data, modified_blocks);
2433
2434         /*
2435                 Get central block
2436         */
2437         MapBlock *block = getBlockNoCreateNoEx(p);
2438
2439 #if 0
2440         /*
2441                 Check result
2442         */
2443         if(block)
2444         {
2445                 bool erroneus_content = false;
2446                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2447                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2448                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2449                 {
2450                         v3s16 p(x0,y0,z0);
2451                         MapNode n = block->getNode(p);
2452                         if(n.getContent() == CONTENT_IGNORE)
2453                         {
2454                                 dstream<<"CONTENT_IGNORE at "
2455                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2456                                                 <<std::endl;
2457                                 erroneus_content = true;
2458                                 assert(0);
2459                         }
2460                 }
2461                 if(erroneus_content)
2462                 {
2463                         assert(0);
2464                 }
2465         }
2466 #endif
2467
2468 #if 0
2469         /*
2470                 Generate a completely empty block
2471         */
2472         if(block)
2473         {
2474                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2475                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2476                 {
2477                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2478                         {
2479                                 MapNode n;
2480                                 if(y0%2==0)
2481                                         n.setContent(CONTENT_AIR);
2482                                 else
2483                                         n.setContent(CONTENT_STONE);
2484                                 block->setNode(v3s16(x0,y0,z0), n);
2485                         }
2486                 }
2487         }
2488 #endif
2489
2490         if(enable_mapgen_debug_info == false)
2491                 timer.stop(true); // Hide output
2492
2493         return block;
2494 }
2495
2496 MapBlock * ServerMap::createBlock(v3s16 p)
2497 {
2498         DSTACKF("%s: p=(%d,%d,%d)",
2499                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2500         
2501         /*
2502                 Do not create over-limit
2503         */
2504         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2505         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2506         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2507         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2508         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2509         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2510                 throw InvalidPositionException("createBlock(): pos. over limit");
2511         
2512         v2s16 p2d(p.X, p.Z);
2513         s16 block_y = p.Y;
2514         /*
2515                 This will create or load a sector if not found in memory.
2516                 If block exists on disk, it will be loaded.
2517
2518                 NOTE: On old save formats, this will be slow, as it generates
2519                       lighting on blocks for them.
2520         */
2521         ServerMapSector *sector;
2522         try{
2523                 sector = (ServerMapSector*)createSector(p2d);
2524                 assert(sector->getId() == MAPSECTOR_SERVER);
2525         }
2526         catch(InvalidPositionException &e)
2527         {
2528                 dstream<<"createBlock: createSector() failed"<<std::endl;
2529                 throw e;
2530         }
2531         /*
2532                 NOTE: This should not be done, or at least the exception
2533                 should not be passed on as std::exception, because it
2534                 won't be catched at all.
2535         */
2536         /*catch(std::exception &e)
2537         {
2538                 dstream<<"createBlock: createSector() failed: "
2539                                 <<e.what()<<std::endl;
2540                 throw e;
2541         }*/
2542
2543         /*
2544                 Try to get a block from the sector
2545         */
2546
2547         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2548         if(block)
2549         {
2550                 if(block->isDummy())
2551                         block->unDummify();
2552                 return block;
2553         }
2554         // Create blank
2555         block = sector->createBlankBlock(block_y);
2556         return block;
2557 }
2558
2559 MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
2560 {
2561         DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
2562                         __FUNCTION_NAME,
2563                         p.X, p.Y, p.Z, allow_generate);
2564         
2565         {
2566                 MapBlock *block = getBlockNoCreateNoEx(p);
2567                 if(block && block->isDummy() == false)
2568                         return block;
2569         }
2570
2571         {
2572                 MapBlock *block = loadBlock(p);
2573                 if(block)
2574                         return block;
2575         }
2576
2577         if(allow_generate)
2578         {
2579                 core::map<v3s16, MapBlock*> modified_blocks;
2580                 MapBlock *block = generateBlock(p, modified_blocks);
2581                 if(block)
2582                 {
2583                         MapEditEvent event;
2584                         event.type = MEET_OTHER;
2585                         event.p = p;
2586
2587                         // Copy modified_blocks to event
2588                         for(core::map<v3s16, MapBlock*>::Iterator
2589                                         i = modified_blocks.getIterator();
2590                                         i.atEnd()==false; i++)
2591                         {
2592                                 event.modified_blocks.insert(i.getNode()->getKey(), false);
2593                         }
2594
2595                         // Queue event
2596                         dispatchEvent(&event);
2597                                                                 
2598                         return block;
2599                 }
2600         }
2601
2602         return NULL;
2603 }
2604
2605 #if 0
2606         /*
2607                 Do not generate over-limit
2608         */
2609         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2610         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2611         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2612         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2613         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2614         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2615                 throw InvalidPositionException("emergeBlock(): pos. over limit");
2616         
2617         v2s16 p2d(p.X, p.Z);
2618         s16 block_y = p.Y;
2619         /*
2620                 This will create or load a sector if not found in memory.
2621                 If block exists on disk, it will be loaded.
2622         */
2623         ServerMapSector *sector;
2624         try{
2625                 sector = createSector(p2d);
2626                 //sector = emergeSector(p2d, changed_blocks);
2627         }
2628         catch(InvalidPositionException &e)
2629         {
2630                 dstream<<"emergeBlock: createSector() failed: "
2631                                 <<e.what()<<std::endl;
2632                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2633                                 <<std::endl
2634                                 <<"You could try to delete it."<<std::endl;
2635                 throw e;
2636         }
2637         catch(VersionMismatchException &e)
2638         {
2639                 dstream<<"emergeBlock: createSector() failed: "
2640                                 <<e.what()<<std::endl;
2641                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2642                                 <<std::endl
2643                                 <<"You could try to delete it."<<std::endl;
2644                 throw e;
2645         }
2646
2647         /*
2648                 Try to get a block from the sector
2649         */
2650
2651         bool does_not_exist = false;
2652         bool lighting_expired = false;
2653         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2654         
2655         // If not found, try loading from disk
2656         if(block == NULL)
2657         {
2658                 block = loadBlock(p);
2659         }
2660         
2661         // Handle result
2662         if(block == NULL)
2663         {
2664                 does_not_exist = true;
2665         }
2666         else if(block->isDummy() == true)
2667         {
2668                 does_not_exist = true;
2669         }
2670         else if(block->getLightingExpired())
2671         {
2672                 lighting_expired = true;
2673         }
2674         else
2675         {
2676                 // Valid block
2677                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
2678                 return block;
2679         }
2680         
2681         /*
2682                 If block was not found on disk and not going to generate a
2683                 new one, make sure there is a dummy block in place.
2684         */
2685         if(only_from_disk && (does_not_exist || lighting_expired))
2686         {
2687                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
2688
2689                 if(block == NULL)
2690                 {
2691                         // Create dummy block
2692                         block = new MapBlock(this, p, true);
2693
2694                         // Add block to sector
2695                         sector->insertBlock(block);
2696                 }
2697                 // Done.
2698                 return block;
2699         }
2700
2701         //dstream<<"Not found on disk, generating."<<std::endl;
2702         // 0ms
2703         //TimeTaker("emergeBlock() generate");
2704
2705         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
2706
2707         /*
2708                 If the block doesn't exist, generate the block.
2709         */
2710         if(does_not_exist)
2711         {
2712                 block = generateBlock(p, block, sector, changed_blocks,
2713                                 lighting_invalidated_blocks); 
2714         }
2715
2716         if(lighting_expired)
2717         {
2718                 lighting_invalidated_blocks.insert(p, block);
2719         }
2720
2721 #if 0
2722         /*
2723                 Initially update sunlight
2724         */
2725         {
2726                 core::map<v3s16, bool> light_sources;
2727                 bool black_air_left = false;
2728                 bool bottom_invalid =
2729                                 block->propagateSunlight(light_sources, true,
2730                                 &black_air_left);
2731
2732                 // If sunlight didn't reach everywhere and part of block is
2733                 // above ground, lighting has to be properly updated
2734                 //if(black_air_left && some_part_underground)
2735                 if(black_air_left)
2736                 {
2737                         lighting_invalidated_blocks[block->getPos()] = block;
2738                 }
2739
2740                 if(bottom_invalid)
2741                 {
2742                         lighting_invalidated_blocks[block->getPos()] = block;
2743                 }
2744         }
2745 #endif
2746         
2747         return block;
2748 }
2749 #endif
2750
2751 s16 ServerMap::findGroundLevel(v2s16 p2d)
2752 {
2753 #if 0
2754         /*
2755                 Uh, just do something random...
2756         */
2757         // Find existing map from top to down
2758         s16 max=63;
2759         s16 min=-64;
2760         v3s16 p(p2d.X, max, p2d.Y);
2761         for(; p.Y>min; p.Y--)
2762         {
2763                 MapNode n = getNodeNoEx(p);
2764                 if(n.getContent() != CONTENT_IGNORE)
2765                         break;
2766         }
2767         if(p.Y == min)
2768                 goto plan_b;
2769         // If this node is not air, go to plan b
2770         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2771                 goto plan_b;
2772         // Search existing walkable and return it
2773         for(; p.Y>min; p.Y--)
2774         {
2775                 MapNode n = getNodeNoEx(p);
2776                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2777                         return p.Y;
2778         }
2779
2780         // Move to plan b
2781 plan_b:
2782 #endif
2783
2784         /*
2785                 Determine from map generator noise functions
2786         */
2787         
2788         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2789         return level;
2790
2791         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2792         //return (s16)level;
2793 }
2794
2795 void ServerMap::createDatabase() {
2796         int e;
2797         assert(m_database);
2798         e = sqlite3_exec(m_database,
2799                 "CREATE TABLE IF NOT EXISTS `blocks` ("
2800                         "`pos` INT NOT NULL PRIMARY KEY,"
2801                         "`data` BLOB"
2802                 ");"
2803         , NULL, NULL, NULL);
2804         if(e == SQLITE_ABORT)
2805                 throw FileNotGoodException("Could not create database structure");
2806         else
2807                 dstream<<"Server: Database structure was created";
2808 }
2809
2810 void ServerMap::verifyDatabase() {
2811         if(m_database)
2812                 return;
2813         
2814         {
2815                 std::string dbp = m_savedir + "/map.sqlite";
2816                 bool needs_create = false;
2817                 int d;
2818                 
2819                 /*
2820                         Open the database connection
2821                 */
2822         
2823                 createDirs(m_savedir);
2824         
2825                 if(!fs::PathExists(dbp))
2826                         needs_create = true;
2827         
2828                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
2829                 if(d != SQLITE_OK) {
2830                         dstream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
2831                         throw FileNotGoodException("Cannot open database file");
2832                 }
2833                 
2834                 if(needs_create)
2835                         createDatabase();
2836         
2837                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
2838                 if(d != SQLITE_OK) {
2839                         dstream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2840                         throw FileNotGoodException("Cannot prepare read statement");
2841                 }
2842                 
2843                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
2844                 if(d != SQLITE_OK) {
2845                         dstream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2846                         throw FileNotGoodException("Cannot prepare write statement");
2847                 }
2848                 
2849                 dstream<<"Server: Database opened"<<std::endl;
2850         }
2851 }
2852
2853 bool ServerMap::loadFromFolders() {
2854         if(!m_database && !fs::PathExists(m_savedir + "/map.sqlite"))
2855                 return true;
2856         return false;
2857 }
2858
2859 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
2860         return (sqlite3_int64)pos.Z*16777216 +
2861                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
2862 }
2863
2864 void ServerMap::createDirs(std::string path)
2865 {
2866         if(fs::CreateAllDirs(path) == false)
2867         {
2868                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2869                                 <<"\""<<path<<"\""<<std::endl;
2870                 throw BaseException("ServerMap failed to create directory");
2871         }
2872 }
2873
2874 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2875 {
2876         char cc[9];
2877         switch(layout)
2878         {
2879                 case 1:
2880                         snprintf(cc, 9, "%.4x%.4x",
2881                                 (unsigned int)pos.X&0xffff,
2882                                 (unsigned int)pos.Y&0xffff);
2883
2884                         return m_savedir + "/sectors/" + cc;
2885                 case 2:
2886                         snprintf(cc, 9, "%.3x/%.3x",
2887                                 (unsigned int)pos.X&0xfff,
2888                                 (unsigned int)pos.Y&0xfff);
2889
2890                         return m_savedir + "/sectors2/" + cc;
2891                 default:
2892                         assert(false);
2893         }
2894 }
2895
2896 v2s16 ServerMap::getSectorPos(std::string dirname)
2897 {
2898         unsigned int x, y;
2899         int r;
2900         size_t spos = dirname.rfind('/') + 1;
2901         assert(spos != std::string::npos);
2902         if(dirname.size() - spos == 8)
2903         {
2904                 // Old layout
2905                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2906         }
2907         else if(dirname.size() - spos == 3)
2908         {
2909                 // New layout
2910                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
2911                 // Sign-extend the 12 bit values up to 16 bits...
2912                 if(x&0x800) x|=0xF000;
2913                 if(y&0x800) y|=0xF000;
2914         }
2915         else
2916         {
2917                 assert(false);
2918         }
2919         assert(r == 2);
2920         v2s16 pos((s16)x, (s16)y);
2921         return pos;
2922 }
2923
2924 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2925 {
2926         v2s16 p2d = getSectorPos(sectordir);
2927
2928         if(blockfile.size() != 4){
2929                 throw InvalidFilenameException("Invalid block filename");
2930         }
2931         unsigned int y;
2932         int r = sscanf(blockfile.c_str(), "%4x", &y);
2933         if(r != 1)
2934                 throw InvalidFilenameException("Invalid block filename");
2935         return v3s16(p2d.X, y, p2d.Y);
2936 }
2937
2938 std::string ServerMap::getBlockFilename(v3s16 p)
2939 {
2940         char cc[5];
2941         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2942         return cc;
2943 }
2944
2945 void ServerMap::save(bool only_changed)
2946 {
2947         DSTACK(__FUNCTION_NAME);
2948         if(m_map_saving_enabled == false)
2949         {
2950                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2951                 return;
2952         }
2953         
2954         if(only_changed == false)
2955                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2956                                 <<std::endl;
2957         
2958         if(only_changed == false || m_map_metadata_changed)
2959         {
2960                 saveMapMeta();
2961         }
2962
2963         u32 sector_meta_count = 0;
2964         u32 block_count = 0;
2965         u32 block_count_all = 0; // Number of blocks in memory
2966         
2967         beginSave();
2968         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2969         for(; i.atEnd() == false; i++)
2970         {
2971                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2972                 assert(sector->getId() == MAPSECTOR_SERVER);
2973         
2974                 if(sector->differs_from_disk || only_changed == false)
2975                 {
2976                         saveSectorMeta(sector);
2977                         sector_meta_count++;
2978                 }
2979                 core::list<MapBlock*> blocks;
2980                 sector->getBlocks(blocks);
2981                 core::list<MapBlock*>::Iterator j;
2982                 
2983                 //sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL);
2984                 for(j=blocks.begin(); j!=blocks.end(); j++)
2985                 {
2986                         MapBlock *block = *j;
2987                         
2988                         block_count_all++;
2989
2990                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
2991                                         || only_changed == false)
2992                         {
2993                                 saveBlock(block);
2994                                 block_count++;
2995
2996                                 /*dstream<<"ServerMap: Written block ("
2997                                                 <<block->getPos().X<<","
2998                                                 <<block->getPos().Y<<","
2999                                                 <<block->getPos().Z<<")"
3000                                                 <<std::endl;*/
3001                         }
3002                 //sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL);
3003                 }
3004         }
3005         endSave();
3006
3007         /*
3008                 Only print if something happened or saved whole map
3009         */
3010         if(only_changed == false || sector_meta_count != 0
3011                         || block_count != 0)
3012         {
3013                 dstream<<DTIME<<"ServerMap: Written: "
3014                                 <<sector_meta_count<<" sector metadata files, "
3015                                 <<block_count<<" block files"
3016                                 <<", "<<block_count_all<<" blocks in memory."
3017                                 <<std::endl;
3018         }
3019 }
3020
3021 void ServerMap::saveMapMeta()
3022 {
3023         DSTACK(__FUNCTION_NAME);
3024         
3025         dstream<<"INFO: ServerMap::saveMapMeta(): "
3026                         <<"seed="<<m_seed
3027                         <<std::endl;
3028
3029         createDirs(m_savedir);
3030         
3031         std::string fullpath = m_savedir + "/map_meta.txt";
3032         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
3033         if(os.good() == false)
3034         {
3035                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
3036                                 <<"could not open"<<fullpath<<std::endl;
3037                 throw FileNotGoodException("Cannot open chunk metadata");
3038         }
3039         
3040         Settings params;
3041         params.setU64("seed", m_seed);
3042
3043         params.writeLines(os);
3044
3045         os<<"[end_of_params]\n";
3046         
3047         m_map_metadata_changed = false;
3048 }
3049
3050 void ServerMap::loadMapMeta()
3051 {
3052         DSTACK(__FUNCTION_NAME);
3053         
3054         dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
3055                         <<std::endl;
3056
3057         std::string fullpath = m_savedir + "/map_meta.txt";
3058         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3059         if(is.good() == false)
3060         {
3061                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
3062                                 <<"could not open"<<fullpath<<std::endl;
3063                 throw FileNotGoodException("Cannot open map metadata");
3064         }
3065
3066         Settings params;
3067
3068         for(;;)
3069         {
3070                 if(is.eof())
3071                         throw SerializationError
3072                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3073                 std::string line;
3074                 std::getline(is, line);
3075                 std::string trimmedline = trim(line);
3076                 if(trimmedline == "[end_of_params]")
3077                         break;
3078                 params.parseConfigLine(line);
3079         }
3080
3081         m_seed = params.getU64("seed");
3082
3083         dstream<<"INFO: ServerMap::loadMapMeta(): "
3084                         <<"seed="<<m_seed
3085                         <<std::endl;
3086 }
3087
3088 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3089 {
3090         DSTACK(__FUNCTION_NAME);
3091         // Format used for writing
3092         u8 version = SER_FMT_VER_HIGHEST;
3093         // Get destination
3094         v2s16 pos = sector->getPos();
3095         std::string dir = getSectorDir(pos);
3096         createDirs(dir);
3097         
3098         std::string fullpath = dir + "/meta";
3099         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3100         if(o.good() == false)
3101                 throw FileNotGoodException("Cannot open sector metafile");
3102
3103         sector->serialize(o, version);
3104         
3105         sector->differs_from_disk = false;
3106 }
3107
3108 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3109 {
3110         DSTACK(__FUNCTION_NAME);
3111         // Get destination
3112         v2s16 p2d = getSectorPos(sectordir);
3113
3114         ServerMapSector *sector = NULL;
3115
3116         std::string fullpath = sectordir + "/meta";
3117         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3118         if(is.good() == false)
3119         {
3120                 // If the directory exists anyway, it probably is in some old
3121                 // format. Just go ahead and create the sector.
3122                 if(fs::PathExists(sectordir))
3123                 {
3124                         /*dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
3125                                         <<fullpath<<" doesn't exist but directory does."
3126                                         <<" Continuing with a sector with no metadata."
3127                                         <<std::endl;*/
3128                         sector = new ServerMapSector(this, p2d);
3129                         m_sectors.insert(p2d, sector);
3130                 }
3131                 else
3132                 {
3133                         throw FileNotGoodException("Cannot open sector metafile");
3134                 }
3135         }
3136         else
3137         {
3138                 sector = ServerMapSector::deSerialize
3139                                 (is, this, p2d, m_sectors);
3140                 if(save_after_load)
3141                         saveSectorMeta(sector);
3142         }
3143         
3144         sector->differs_from_disk = false;
3145
3146         return sector;
3147 }
3148
3149 bool ServerMap::loadSectorMeta(v2s16 p2d)
3150 {
3151         DSTACK(__FUNCTION_NAME);
3152
3153         MapSector *sector = NULL;
3154
3155         // The directory layout we're going to load from.
3156         //  1 - original sectors/xxxxzzzz/
3157         //  2 - new sectors2/xxx/zzz/
3158         //  If we load from anything but the latest structure, we will
3159         //  immediately save to the new one, and remove the old.
3160         int loadlayout = 1;
3161         std::string sectordir1 = getSectorDir(p2d, 1);
3162         std::string sectordir;
3163         if(fs::PathExists(sectordir1))
3164         {
3165                 sectordir = sectordir1;
3166         }
3167         else
3168         {
3169                 loadlayout = 2;
3170                 sectordir = getSectorDir(p2d, 2);
3171         }
3172
3173         try{
3174                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3175         }
3176         catch(InvalidFilenameException &e)
3177         {
3178                 return false;
3179         }
3180         catch(FileNotGoodException &e)
3181         {
3182                 return false;
3183         }
3184         catch(std::exception &e)
3185         {
3186                 return false;
3187         }
3188         
3189         return true;
3190 }
3191
3192 #if 0
3193 bool ServerMap::loadSectorFull(v2s16 p2d)
3194 {
3195         DSTACK(__FUNCTION_NAME);
3196
3197         MapSector *sector = NULL;
3198
3199         // The directory layout we're going to load from.
3200         //  1 - original sectors/xxxxzzzz/
3201         //  2 - new sectors2/xxx/zzz/
3202         //  If we load from anything but the latest structure, we will
3203         //  immediately save to the new one, and remove the old.
3204         int loadlayout = 1;
3205         std::string sectordir1 = getSectorDir(p2d, 1);
3206         std::string sectordir;
3207         if(fs::PathExists(sectordir1))
3208         {
3209                 sectordir = sectordir1;
3210         }
3211         else
3212         {
3213                 loadlayout = 2;
3214                 sectordir = getSectorDir(p2d, 2);
3215         }
3216
3217         try{
3218                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3219         }
3220         catch(InvalidFilenameException &e)
3221         {
3222                 return false;
3223         }
3224         catch(FileNotGoodException &e)
3225         {
3226                 return false;
3227         }
3228         catch(std::exception &e)
3229         {
3230                 return false;
3231         }
3232         
3233         /*
3234                 Load blocks
3235         */
3236         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3237                         (sectordir);
3238         std::vector<fs::DirListNode>::iterator i2;
3239         for(i2=list2.begin(); i2!=list2.end(); i2++)
3240         {
3241                 // We want files
3242                 if(i2->dir)
3243                         continue;
3244                 try{
3245                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3246                 }
3247                 catch(InvalidFilenameException &e)
3248                 {
3249                         // This catches unknown crap in directory
3250                 }
3251         }
3252
3253         if(loadlayout != 2)
3254         {
3255                 dstream<<"Sector converted to new layout - deleting "<<
3256                         sectordir1<<std::endl;
3257                 fs::RecursiveDelete(sectordir1);
3258         }
3259
3260         return true;
3261 }
3262 #endif
3263
3264 void ServerMap::beginSave() {
3265         verifyDatabase();
3266         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3267                 dstream<<"WARNING: beginSave() failed, saving might be slow.";
3268 }
3269
3270 void ServerMap::endSave() {
3271         verifyDatabase();
3272         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3273                 dstream<<"WARNING: endSave() failed, map might not have saved.";
3274 }
3275
3276 void ServerMap::saveBlock(MapBlock *block)
3277 {
3278         DSTACK(__FUNCTION_NAME);
3279         /*
3280                 Dummy blocks are not written
3281         */
3282         if(block->isDummy())
3283         {
3284                 /*v3s16 p = block->getPos();
3285                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3286                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3287                 return;
3288         }
3289
3290         // Format used for writing
3291         u8 version = SER_FMT_VER_HIGHEST;
3292         // Get destination
3293         v3s16 p3d = block->getPos();
3294         
3295         
3296 #if 0
3297         v2s16 p2d(p3d.X, p3d.Z);
3298         std::string sectordir = getSectorDir(p2d);
3299
3300         createDirs(sectordir);
3301
3302         std::string fullpath = sectordir+"/"+getBlockFilename(p3d);
3303         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3304         if(o.good() == false)
3305                 throw FileNotGoodException("Cannot open block data");
3306 #endif
3307         /*
3308                 [0] u8 serialization version
3309                 [1] data
3310         */
3311         
3312         verifyDatabase();
3313         
3314         std::ostringstream o(std::ios_base::binary);
3315         
3316         o.write((char*)&version, 1);
3317         
3318         // Write basic data
3319         block->serialize(o, version);
3320         
3321         // Write extra data stored on disk
3322         block->serializeDiskExtra(o, version);
3323         
3324         // Write block to database
3325         
3326         std::string tmp = o.str();
3327         const char *bytes = tmp.c_str();
3328         
3329         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
3330                 dstream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3331         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
3332                 dstream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3333         int written = sqlite3_step(m_database_write);
3334         if(written != SQLITE_DONE)
3335                 dstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3336                 <<sqlite3_errmsg(m_database)<<std::endl;
3337         // Make ready for later reuse
3338         sqlite3_reset(m_database_write);
3339         
3340         // We just wrote it to the disk so clear modified flag
3341         block->resetModified();
3342 }
3343
3344 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3345 {
3346         DSTACK(__FUNCTION_NAME);
3347
3348         std::string fullpath = sectordir+"/"+blockfile;
3349         try{
3350
3351                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3352                 if(is.good() == false)
3353                         throw FileNotGoodException("Cannot open block file");
3354                 
3355                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3356                 v2s16 p2d(p3d.X, p3d.Z);
3357                 
3358                 assert(sector->getPos() == p2d);
3359                 
3360                 u8 version = SER_FMT_VER_INVALID;
3361                 is.read((char*)&version, 1);
3362
3363                 if(is.fail())
3364                         throw SerializationError("ServerMap::loadBlock(): Failed"
3365                                         " to read MapBlock version");
3366
3367                 /*u32 block_size = MapBlock::serializedLength(version);
3368                 SharedBuffer<u8> data(block_size);
3369                 is.read((char*)*data, block_size);*/
3370
3371                 // This will always return a sector because we're the server
3372                 //MapSector *sector = emergeSector(p2d);
3373
3374                 MapBlock *block = NULL;
3375                 bool created_new = false;
3376                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3377                 if(block == NULL)
3378                 {
3379                         block = sector->createBlankBlockNoInsert(p3d.Y);
3380                         created_new = true;
3381                 }
3382                 
3383                 // Read basic data
3384                 block->deSerialize(is, version);
3385
3386                 // Read extra data stored on disk
3387                 block->deSerializeDiskExtra(is, version);
3388                 
3389                 // If it's a new block, insert it to the map
3390                 if(created_new)
3391                         sector->insertBlock(block);
3392                 
3393                 /*
3394                         Save blocks loaded in old format in new format
3395                 */
3396
3397                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3398                 {
3399                         saveBlock(block);
3400                 }
3401                 
3402                 // We just loaded it from the disk, so it's up-to-date.
3403                 block->resetModified();
3404
3405         }
3406         catch(SerializationError &e)
3407         {
3408                 dstream<<"WARNING: Invalid block data on disk "
3409                                 <<"fullpath="<<fullpath
3410                                 <<" (SerializationError). "
3411                                 <<"what()="<<e.what()
3412                                 <<std::endl;
3413                                 //" Ignoring. A new one will be generated.
3414                 assert(0);
3415
3416                 // TODO: Backup file; name is in fullpath.
3417         }
3418 }
3419
3420 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3421 {
3422         DSTACK(__FUNCTION_NAME);
3423
3424         try {
3425                 std::istringstream is(*blob, std::ios_base::binary);
3426                 
3427                 u8 version = SER_FMT_VER_INVALID;
3428                 is.read((char*)&version, 1);
3429
3430                 if(is.fail())
3431                         throw SerializationError("ServerMap::loadBlock(): Failed"
3432                                         " to read MapBlock version");
3433
3434                 /*u32 block_size = MapBlock::serializedLength(version);
3435                 SharedBuffer<u8> data(block_size);
3436                 is.read((char*)*data, block_size);*/
3437
3438                 // This will always return a sector because we're the server
3439                 //MapSector *sector = emergeSector(p2d);
3440
3441                 MapBlock *block = NULL;
3442                 bool created_new = false;
3443                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3444                 if(block == NULL)
3445                 {
3446                         block = sector->createBlankBlockNoInsert(p3d.Y);
3447                         created_new = true;
3448                 }
3449                 
3450                 // Read basic data
3451                 block->deSerialize(is, version);
3452
3453                 // Read extra data stored on disk
3454                 block->deSerializeDiskExtra(is, version);
3455                 
3456                 // If it's a new block, insert it to the map
3457                 if(created_new)
3458                         sector->insertBlock(block);
3459                 
3460                 /*
3461                         Save blocks loaded in old format in new format
3462                 */
3463
3464                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3465                 {
3466                         saveBlock(block);
3467                 }
3468                 
3469                 // We just loaded it from, so it's up-to-date.
3470                 block->resetModified();
3471
3472         }
3473         catch(SerializationError &e)
3474         {
3475                 dstream<<"WARNING: Invalid block data in database "
3476                                 <<" (SerializationError). "
3477                                 <<"what()="<<e.what()
3478                                 <<std::endl;
3479                                 //" Ignoring. A new one will be generated.
3480                 assert(0);
3481
3482                 // TODO: Copy to a backup database.
3483         }
3484 }
3485
3486 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3487 {
3488         DSTACK(__FUNCTION_NAME);
3489
3490         v2s16 p2d(blockpos.X, blockpos.Z);
3491
3492         if(!loadFromFolders()) {
3493                 verifyDatabase();
3494                 
3495                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3496                         dstream<<"WARNING: Could not bind block position for load: "
3497                                 <<sqlite3_errmsg(m_database)<<std::endl;
3498                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3499                         /*
3500                                 Make sure sector is loaded
3501                         */
3502                         MapSector *sector = createSector(p2d);
3503                         
3504                         /*
3505                                 Load block
3506                         */
3507                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3508                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3509                         
3510                         std::string datastr(data, len);
3511                         
3512                         loadBlock(&datastr, blockpos, sector, false);
3513
3514                         sqlite3_step(m_database_read);
3515                         // We should never get more than 1 row, so ok to reset
3516                         sqlite3_reset(m_database_read);
3517
3518                         return getBlockNoCreateNoEx(blockpos);
3519                 }
3520                 sqlite3_reset(m_database_read);
3521                 
3522                 // Not found in database, try the files
3523         }
3524
3525         // The directory layout we're going to load from.
3526         //  1 - original sectors/xxxxzzzz/
3527         //  2 - new sectors2/xxx/zzz/
3528         //  If we load from anything but the latest structure, we will
3529         //  immediately save to the new one, and remove the old.
3530         int loadlayout = 1;
3531         std::string sectordir1 = getSectorDir(p2d, 1);
3532         std::string sectordir;
3533         if(fs::PathExists(sectordir1))
3534         {
3535                 sectordir = sectordir1;
3536         }
3537         else
3538         {
3539                 loadlayout = 2;
3540                 sectordir = getSectorDir(p2d, 2);
3541         }
3542         
3543         /*
3544                 Make sure sector is loaded
3545         */
3546         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3547         if(sector == NULL)
3548         {
3549                 try{
3550                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3551                 }
3552                 catch(InvalidFilenameException &e)
3553                 {
3554                         return false;
3555                 }
3556                 catch(FileNotGoodException &e)
3557                 {
3558                         return false;
3559                 }
3560                 catch(std::exception &e)
3561                 {
3562                         return false;
3563                 }
3564         }
3565         
3566         /*
3567                 Make sure file exists
3568         */
3569
3570         std::string blockfilename = getBlockFilename(blockpos);
3571         if(fs::PathExists(sectordir+"/"+blockfilename) == false)
3572                 return NULL;
3573
3574         /*
3575                 Load block and save it to the database
3576         */
3577         loadBlock(sectordir, blockfilename, sector, true);
3578         return getBlockNoCreateNoEx(blockpos);
3579 }
3580
3581 void ServerMap::PrintInfo(std::ostream &out)
3582 {
3583         out<<"ServerMap: ";
3584 }
3585
3586 #ifndef SERVER
3587
3588 /*
3589         ClientMap
3590 */
3591
3592 ClientMap::ClientMap(
3593                 Client *client,
3594                 MapDrawControl &control,
3595                 scene::ISceneNode* parent,
3596                 scene::ISceneManager* mgr,
3597                 s32 id
3598 ):
3599         Map(dout_client),
3600         scene::ISceneNode(parent, mgr, id),
3601         m_client(client),
3602         m_control(control),
3603         m_camera_position(0,0,0),
3604         m_camera_direction(0,0,1)
3605 {
3606         m_camera_mutex.Init();
3607         assert(m_camera_mutex.IsInitialized());
3608         
3609         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3610                         BS*1000000,BS*1000000,BS*1000000);
3611 }
3612
3613 ClientMap::~ClientMap()
3614 {
3615         /*JMutexAutoLock lock(mesh_mutex);
3616         
3617         if(mesh != NULL)
3618         {
3619                 mesh->drop();
3620                 mesh = NULL;
3621         }*/
3622 }
3623
3624 MapSector * ClientMap::emergeSector(v2s16 p2d)
3625 {
3626         DSTACK(__FUNCTION_NAME);
3627         // Check that it doesn't exist already
3628         try{
3629                 return getSectorNoGenerate(p2d);
3630         }
3631         catch(InvalidPositionException &e)
3632         {
3633         }
3634         
3635         // Create a sector
3636         ClientMapSector *sector = new ClientMapSector(this, p2d);
3637         
3638         {
3639                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3640                 m_sectors.insert(p2d, sector);
3641         }
3642         
3643         return sector;
3644 }
3645
3646 #if 0
3647 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3648 {
3649         DSTACK(__FUNCTION_NAME);
3650         ClientMapSector *sector = NULL;
3651
3652         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3653         
3654         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3655
3656         if(n != NULL)
3657         {
3658                 sector = (ClientMapSector*)n->getValue();
3659                 assert(sector->getId() == MAPSECTOR_CLIENT);
3660         }
3661         else
3662         {
3663                 sector = new ClientMapSector(this, p2d);
3664                 {
3665                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3666                         m_sectors.insert(p2d, sector);
3667                 }
3668         }
3669
3670         sector->deSerialize(is);
3671 }
3672 #endif
3673
3674 void ClientMap::OnRegisterSceneNode()
3675 {
3676         if(IsVisible)
3677         {
3678                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3679                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3680         }
3681
3682         ISceneNode::OnRegisterSceneNode();
3683 }
3684
3685 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3686 {
3687         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3688         DSTACK(__FUNCTION_NAME);
3689
3690         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3691         
3692         /*
3693                 This is called two times per frame, reset on the non-transparent one
3694         */
3695         if(pass == scene::ESNRP_SOLID)
3696         {
3697                 m_last_drawn_sectors.clear();
3698         }
3699
3700         /*
3701                 Get time for measuring timeout.
3702                 
3703                 Measuring time is very useful for long delays when the
3704                 machine is swapping a lot.
3705         */
3706         int time1 = time(0);
3707
3708         //u32 daynight_ratio = m_client->getDayNightRatio();
3709
3710         m_camera_mutex.Lock();
3711         v3f camera_position = m_camera_position;
3712         v3f camera_direction = m_camera_direction;
3713         m_camera_mutex.Unlock();
3714
3715         /*
3716                 Get all blocks and draw all visible ones
3717         */
3718
3719         v3s16 cam_pos_nodes(
3720                         camera_position.X / BS,
3721                         camera_position.Y / BS,
3722                         camera_position.Z / BS);
3723
3724         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3725
3726         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3727         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3728
3729         // Take a fair amount as we will be dropping more out later
3730         v3s16 p_blocks_min(
3731                         p_nodes_min.X / MAP_BLOCKSIZE - 2,
3732                         p_nodes_min.Y / MAP_BLOCKSIZE - 2,
3733                         p_nodes_min.Z / MAP_BLOCKSIZE - 2);
3734         v3s16 p_blocks_max(
3735                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3736                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3737                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3738         
3739         u32 vertex_count = 0;
3740         
3741         // For limiting number of mesh updates per frame
3742         u32 mesh_update_count = 0;
3743         
3744         u32 blocks_would_have_drawn = 0;
3745         u32 blocks_drawn = 0;
3746
3747         int timecheck_counter = 0;
3748         core::map<v2s16, MapSector*>::Iterator si;
3749         si = m_sectors.getIterator();
3750         for(; si.atEnd() == false; si++)
3751         {
3752                 {
3753                         timecheck_counter++;
3754                         if(timecheck_counter > 50)
3755                         {
3756                                 timecheck_counter = 0;
3757                                 int time2 = time(0);
3758                                 if(time2 > time1 + 4)
3759                                 {
3760                                         dstream<<"ClientMap::renderMap(): "
3761                                                 "Rendering takes ages, returning."
3762                                                 <<std::endl;
3763                                         return;
3764                                 }
3765                         }
3766                 }
3767
3768                 MapSector *sector = si.getNode()->getValue();
3769                 v2s16 sp = sector->getPos();
3770                 
3771                 if(m_control.range_all == false)
3772                 {
3773                         if(sp.X < p_blocks_min.X
3774                         || sp.X > p_blocks_max.X
3775                         || sp.Y < p_blocks_min.Z
3776                         || sp.Y > p_blocks_max.Z)
3777                                 continue;
3778                 }
3779
3780                 core::list< MapBlock * > sectorblocks;
3781                 sector->getBlocks(sectorblocks);
3782                 
3783                 /*
3784                         Draw blocks
3785                 */
3786                 
3787                 u32 sector_blocks_drawn = 0;
3788
3789                 core::list< MapBlock * >::Iterator i;
3790                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3791                 {
3792                         MapBlock *block = *i;
3793
3794                         /*
3795                                 Compare block position to camera position, skip
3796                                 if not seen on display
3797                         */
3798                         
3799                         float range = 100000 * BS;
3800                         if(m_control.range_all == false)
3801                                 range = m_control.wanted_range * BS;
3802                         
3803                         float d = 0.0;
3804                         if(isBlockInSight(block->getPos(), camera_position,
3805                                         camera_direction, range, &d) == false)
3806                         {
3807                                 continue;
3808                         }
3809
3810                         // Okay, this block will be drawn. Reset usage timer.
3811                         block->resetUsageTimer();
3812                         
3813                         // This is ugly (spherical distance limit?)
3814                         /*if(m_control.range_all == false &&
3815                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3816                                 continue;*/
3817
3818 #if 1
3819                         /*
3820                                 Update expired mesh (used for day/night change)
3821
3822                                 It doesn't work exactly like it should now with the
3823                                 tasked mesh update but whatever.
3824                         */
3825
3826                         bool mesh_expired = false;
3827                         
3828                         {
3829                                 JMutexAutoLock lock(block->mesh_mutex);
3830
3831                                 mesh_expired = block->getMeshExpired();
3832
3833                                 // Mesh has not been expired and there is no mesh:
3834                                 // block has no content
3835                                 if(block->mesh == NULL && mesh_expired == false)
3836                                         continue;
3837                         }
3838
3839                         f32 faraway = BS*50;
3840                         //f32 faraway = m_control.wanted_range * BS;
3841                         
3842                         /*
3843                                 This has to be done with the mesh_mutex unlocked
3844                         */
3845                         // Pretty random but this should work somewhat nicely
3846                         if(mesh_expired && (
3847                                         (mesh_update_count < 3
3848                                                 && (d < faraway || mesh_update_count < 2)
3849                                         )
3850                                         || 
3851                                         (m_control.range_all && mesh_update_count < 20)
3852                                 )
3853                         )
3854                         /*if(mesh_expired && mesh_update_count < 6
3855                                         && (d < faraway || mesh_update_count < 3))*/
3856                         {
3857                                 mesh_update_count++;
3858
3859                                 // Mesh has been expired: generate new mesh
3860                                 //block->updateMesh(daynight_ratio);
3861                                 m_client->addUpdateMeshTask(block->getPos());
3862
3863                                 mesh_expired = false;
3864                         }
3865                         
3866 #endif
3867                         /*
3868                                 Draw the faces of the block
3869                         */
3870                         {
3871                                 JMutexAutoLock lock(block->mesh_mutex);
3872
3873                                 scene::SMesh *mesh = block->mesh;
3874
3875                                 if(mesh == NULL)
3876                                         continue;
3877                                 
3878                                 blocks_would_have_drawn++;
3879                                 if(blocks_drawn >= m_control.wanted_max_blocks
3880                                                 && m_control.range_all == false
3881                                                 && d > m_control.wanted_min_range * BS)
3882                                         continue;
3883
3884                                 blocks_drawn++;
3885                                 sector_blocks_drawn++;
3886
3887                                 u32 c = mesh->getMeshBufferCount();
3888
3889                                 for(u32 i=0; i<c; i++)
3890                                 {
3891                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3892                                         const video::SMaterial& material = buf->getMaterial();
3893                                         video::IMaterialRenderer* rnd =
3894                                                         driver->getMaterialRenderer(material.MaterialType);
3895                                         bool transparent = (rnd && rnd->isTransparent());
3896                                         // Render transparent on transparent pass and likewise.
3897                                         if(transparent == is_transparent_pass)
3898                                         {
3899                                                 /*
3900                                                         This *shouldn't* hurt too much because Irrlicht
3901                                                         doesn't change opengl textures if the old
3902                                                         material is set again.
3903                                                 */
3904                                                 driver->setMaterial(buf->getMaterial());
3905                                                 driver->drawMeshBuffer(buf);
3906                                                 vertex_count += buf->getVertexCount();
3907                                         }
3908                                 }
3909                         }
3910                 } // foreach sectorblocks
3911
3912                 if(sector_blocks_drawn != 0)
3913                 {
3914                         m_last_drawn_sectors[sp] = true;
3915                 }
3916         }
3917         
3918         m_control.blocks_drawn = blocks_drawn;
3919         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3920
3921         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3922                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3923 }
3924
3925 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
3926                 core::map<v3s16, MapBlock*> *affected_blocks)
3927 {
3928         bool changed = false;
3929         /*
3930                 Add it to all blocks touching it
3931         */
3932         v3s16 dirs[7] = {
3933                 v3s16(0,0,0), // this
3934                 v3s16(0,0,1), // back
3935                 v3s16(0,1,0), // top
3936                 v3s16(1,0,0), // right
3937                 v3s16(0,0,-1), // front
3938                 v3s16(0,-1,0), // bottom
3939                 v3s16(-1,0,0), // left
3940         };
3941         for(u16 i=0; i<7; i++)
3942         {
3943                 v3s16 p2 = p + dirs[i];
3944                 // Block position of neighbor (or requested) node
3945                 v3s16 blockpos = getNodeBlockPos(p2);
3946                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3947                 if(blockref == NULL)
3948                         continue;
3949                 // Relative position of requested node
3950                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3951                 if(blockref->setTempMod(relpos, mod))
3952                 {
3953                         changed = true;
3954                 }
3955         }
3956         if(changed && affected_blocks!=NULL)
3957         {
3958                 for(u16 i=0; i<7; i++)
3959                 {
3960                         v3s16 p2 = p + dirs[i];
3961                         // Block position of neighbor (or requested) node
3962                         v3s16 blockpos = getNodeBlockPos(p2);
3963                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3964                         if(blockref == NULL)
3965                                 continue;
3966                         affected_blocks->insert(blockpos, blockref);
3967                 }
3968         }
3969         return changed;
3970 }
3971
3972 bool ClientMap::clearTempMod(v3s16 p,
3973                 core::map<v3s16, MapBlock*> *affected_blocks)
3974 {
3975         bool changed = false;
3976         v3s16 dirs[7] = {
3977                 v3s16(0,0,0), // this
3978                 v3s16(0,0,1), // back
3979                 v3s16(0,1,0), // top
3980                 v3s16(1,0,0), // right
3981                 v3s16(0,0,-1), // front
3982                 v3s16(0,-1,0), // bottom
3983                 v3s16(-1,0,0), // left
3984         };
3985         for(u16 i=0; i<7; i++)
3986         {
3987                 v3s16 p2 = p + dirs[i];
3988                 // Block position of neighbor (or requested) node
3989                 v3s16 blockpos = getNodeBlockPos(p2);
3990                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3991                 if(blockref == NULL)
3992                         continue;
3993                 // Relative position of requested node
3994                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3995                 if(blockref->clearTempMod(relpos))
3996                 {
3997                         changed = true;
3998                 }
3999         }
4000         if(changed && affected_blocks!=NULL)
4001         {
4002                 for(u16 i=0; i<7; i++)
4003                 {
4004                         v3s16 p2 = p + dirs[i];
4005                         // Block position of neighbor (or requested) node
4006                         v3s16 blockpos = getNodeBlockPos(p2);
4007                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4008                         if(blockref == NULL)
4009                                 continue;
4010                         affected_blocks->insert(blockpos, blockref);
4011                 }
4012         }
4013         return changed;
4014 }
4015
4016 void ClientMap::expireMeshes(bool only_daynight_diffed)
4017 {
4018         TimeTaker timer("expireMeshes()");
4019
4020         core::map<v2s16, MapSector*>::Iterator si;
4021         si = m_sectors.getIterator();
4022         for(; si.atEnd() == false; si++)
4023         {
4024                 MapSector *sector = si.getNode()->getValue();
4025
4026                 core::list< MapBlock * > sectorblocks;
4027                 sector->getBlocks(sectorblocks);
4028                 
4029                 core::list< MapBlock * >::Iterator i;
4030                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
4031                 {
4032                         MapBlock *block = *i;
4033
4034                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
4035                         {
4036                                 continue;
4037                         }
4038                         
4039                         {
4040                                 JMutexAutoLock lock(block->mesh_mutex);
4041                                 if(block->mesh != NULL)
4042                                 {
4043                                         /*block->mesh->drop();
4044                                         block->mesh = NULL;*/
4045                                         block->setMeshExpired(true);
4046                                 }
4047                         }
4048                 }
4049         }
4050 }
4051
4052 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
4053 {
4054         assert(mapType() == MAPTYPE_CLIENT);
4055
4056         try{
4057                 v3s16 p = blockpos + v3s16(0,0,0);
4058                 MapBlock *b = getBlockNoCreate(p);
4059                 b->updateMesh(daynight_ratio);
4060                 //b->setMeshExpired(true);
4061         }
4062         catch(InvalidPositionException &e){}
4063         // Leading edge
4064         try{
4065                 v3s16 p = blockpos + v3s16(-1,0,0);
4066                 MapBlock *b = getBlockNoCreate(p);
4067                 b->updateMesh(daynight_ratio);
4068                 //b->setMeshExpired(true);
4069         }
4070         catch(InvalidPositionException &e){}
4071         try{
4072                 v3s16 p = blockpos + v3s16(0,-1,0);
4073                 MapBlock *b = getBlockNoCreate(p);
4074                 b->updateMesh(daynight_ratio);
4075                 //b->setMeshExpired(true);
4076         }
4077         catch(InvalidPositionException &e){}
4078         try{
4079                 v3s16 p = blockpos + v3s16(0,0,-1);
4080                 MapBlock *b = getBlockNoCreate(p);
4081                 b->updateMesh(daynight_ratio);
4082                 //b->setMeshExpired(true);
4083         }
4084         catch(InvalidPositionException &e){}
4085 }
4086
4087 #if 0
4088 /*
4089         Update mesh of block in which the node is, and if the node is at the
4090         leading edge, update the appropriate leading blocks too.
4091 */
4092 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
4093 {
4094         v3s16 dirs[4] = {
4095                 v3s16(0,0,0),
4096                 v3s16(-1,0,0),
4097                 v3s16(0,-1,0),
4098                 v3s16(0,0,-1),
4099         };
4100         v3s16 blockposes[4];
4101         for(u32 i=0; i<4; i++)
4102         {
4103                 v3s16 np = nodepos + dirs[i];
4104                 blockposes[i] = getNodeBlockPos(np);
4105                 // Don't update mesh of block if it has been done already
4106                 bool already_updated = false;
4107                 for(u32 j=0; j<i; j++)
4108                 {
4109                         if(blockposes[j] == blockposes[i])
4110                         {
4111                                 already_updated = true;
4112                                 break;
4113                         }
4114                 }
4115                 if(already_updated)
4116                         continue;
4117                 // Update mesh
4118                 MapBlock *b = getBlockNoCreate(blockposes[i]);
4119                 b->updateMesh(daynight_ratio);
4120         }
4121 }
4122 #endif
4123
4124 void ClientMap::PrintInfo(std::ostream &out)
4125 {
4126         out<<"ClientMap: ";
4127 }
4128
4129 #endif // !SERVER
4130
4131 /*
4132         MapVoxelManipulator
4133 */
4134
4135 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4136 {
4137         m_map = map;
4138 }
4139
4140 MapVoxelManipulator::~MapVoxelManipulator()
4141 {
4142         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4143                         <<std::endl;*/
4144 }
4145
4146 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4147 {
4148         TimeTaker timer1("emerge", &emerge_time);
4149
4150         // Units of these are MapBlocks
4151         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4152         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4153
4154         VoxelArea block_area_nodes
4155                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4156
4157         addArea(block_area_nodes);
4158
4159         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4160         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4161         for(s32 x=p_min.X; x<=p_max.X; x++)
4162         {
4163                 v3s16 p(x,y,z);
4164                 core::map<v3s16, bool>::Node *n;
4165                 n = m_loaded_blocks.find(p);
4166                 if(n != NULL)
4167                         continue;
4168                 
4169                 bool block_data_inexistent = false;
4170                 try
4171                 {
4172                         TimeTaker timer1("emerge load", &emerge_load_time);
4173
4174                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
4175                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4176                                         <<" wanted area: ";
4177                         a.print(dstream);
4178                         dstream<<std::endl;*/
4179                         
4180                         MapBlock *block = m_map->getBlockNoCreate(p);
4181                         if(block->isDummy())
4182                                 block_data_inexistent = true;
4183                         else
4184                                 block->copyTo(*this);
4185                 }
4186                 catch(InvalidPositionException &e)
4187                 {
4188                         block_data_inexistent = true;
4189                 }
4190
4191                 if(block_data_inexistent)
4192                 {
4193                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4194                         // Fill with VOXELFLAG_INEXISTENT
4195                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4196                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4197                         {
4198                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4199                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4200                         }
4201                 }
4202
4203                 m_loaded_blocks.insert(p, !block_data_inexistent);
4204         }
4205
4206         //dstream<<"emerge done"<<std::endl;
4207 }
4208
4209 /*
4210         SUGG: Add an option to only update eg. water and air nodes.
4211               This will make it interfere less with important stuff if
4212                   run on background.
4213 */
4214 void MapVoxelManipulator::blitBack
4215                 (core::map<v3s16, MapBlock*> & modified_blocks)
4216 {
4217         if(m_area.getExtent() == v3s16(0,0,0))
4218                 return;
4219         
4220         //TimeTaker timer1("blitBack");
4221
4222         /*dstream<<"blitBack(): m_loaded_blocks.size()="
4223                         <<m_loaded_blocks.size()<<std::endl;*/
4224         
4225         /*
4226                 Initialize block cache
4227         */
4228         v3s16 blockpos_last;
4229         MapBlock *block = NULL;
4230         bool block_checked_in_modified = false;
4231
4232         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4233         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4234         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4235         {
4236                 v3s16 p(x,y,z);
4237
4238                 u8 f = m_flags[m_area.index(p)];
4239                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4240                         continue;
4241
4242                 MapNode &n = m_data[m_area.index(p)];
4243                         
4244                 v3s16 blockpos = getNodeBlockPos(p);
4245                 
4246                 try
4247                 {
4248                         // Get block
4249                         if(block == NULL || blockpos != blockpos_last){
4250                                 block = m_map->getBlockNoCreate(blockpos);
4251                                 blockpos_last = blockpos;
4252                                 block_checked_in_modified = false;
4253                         }
4254                         
4255                         // Calculate relative position in block
4256                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4257
4258                         // Don't continue if nothing has changed here
4259                         if(block->getNode(relpos) == n)
4260                                 continue;
4261
4262                         //m_map->setNode(m_area.MinEdge + p, n);
4263                         block->setNode(relpos, n);
4264                         
4265                         /*
4266                                 Make sure block is in modified_blocks
4267                         */
4268                         if(block_checked_in_modified == false)
4269                         {
4270                                 modified_blocks[blockpos] = block;
4271                                 block_checked_in_modified = true;
4272                         }
4273                 }
4274                 catch(InvalidPositionException &e)
4275                 {
4276                 }
4277         }
4278 }
4279
4280 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4281                 MapVoxelManipulator(map),
4282                 m_create_area(false)
4283 {
4284 }
4285
4286 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4287 {
4288 }
4289
4290 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4291 {
4292         // Just create the area so that it can be pointed to
4293         VoxelManipulator::emerge(a, caller_id);
4294 }
4295
4296 void ManualMapVoxelManipulator::initialEmerge(
4297                 v3s16 blockpos_min, v3s16 blockpos_max)
4298 {
4299         TimeTaker timer1("initialEmerge", &emerge_time);
4300
4301         // Units of these are MapBlocks
4302         v3s16 p_min = blockpos_min;
4303         v3s16 p_max = blockpos_max;
4304
4305         VoxelArea block_area_nodes
4306                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4307         
4308         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4309         if(size_MB >= 1)
4310         {
4311                 dstream<<"initialEmerge: area: ";
4312                 block_area_nodes.print(dstream);
4313                 dstream<<" ("<<size_MB<<"MB)";
4314                 dstream<<std::endl;
4315         }
4316
4317         addArea(block_area_nodes);
4318
4319         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4320         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4321         for(s32 x=p_min.X; x<=p_max.X; x++)
4322         {
4323                 v3s16 p(x,y,z);
4324                 core::map<v3s16, bool>::Node *n;
4325                 n = m_loaded_blocks.find(p);
4326                 if(n != NULL)
4327                         continue;
4328                 
4329                 bool block_data_inexistent = false;
4330                 try
4331                 {
4332                         TimeTaker timer1("emerge load", &emerge_load_time);
4333
4334                         MapBlock *block = m_map->getBlockNoCreate(p);
4335                         if(block->isDummy())
4336                                 block_data_inexistent = true;
4337                         else
4338                                 block->copyTo(*this);
4339                 }
4340                 catch(InvalidPositionException &e)
4341                 {
4342                         block_data_inexistent = true;
4343                 }
4344
4345                 if(block_data_inexistent)
4346                 {
4347                         /*
4348                                 Mark area inexistent
4349                         */
4350                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4351                         // Fill with VOXELFLAG_INEXISTENT
4352                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4353                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4354                         {
4355                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4356                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4357                         }
4358                 }
4359
4360                 m_loaded_blocks.insert(p, !block_data_inexistent);
4361         }
4362 }
4363
4364 void ManualMapVoxelManipulator::blitBackAll(
4365                 core::map<v3s16, MapBlock*> * modified_blocks)
4366 {
4367         if(m_area.getExtent() == v3s16(0,0,0))
4368                 return;
4369         
4370         /*
4371                 Copy data of all blocks
4372         */
4373         for(core::map<v3s16, bool>::Iterator
4374                         i = m_loaded_blocks.getIterator();
4375                         i.atEnd() == false; i++)
4376         {
4377                 v3s16 p = i.getNode()->getKey();
4378                 bool existed = i.getNode()->getValue();
4379                 if(existed == false)
4380                 {
4381                         // The Great Bug was found using this
4382                         /*dstream<<"ManualMapVoxelManipulator::blitBackAll: "
4383                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4384                                         <<std::endl;*/
4385                         continue;
4386                 }
4387                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4388                 if(block == NULL)
4389                 {
4390                         dstream<<"WARNING: "<<__FUNCTION_NAME
4391                                         <<": got NULL block "
4392                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4393                                         <<std::endl;
4394                         continue;
4395                 }
4396
4397                 block->copyFrom(*this);
4398
4399                 if(modified_blocks)
4400                         modified_blocks->insert(p, block);
4401         }
4402 }
4403
4404 //END