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