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