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