]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
d3e8983579a96cf5ff58e078fbbc3e764906dfc3
[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                 Also add horizontal neighbors of node on top of removed node
1209                 because they could be affected of the water on top flowing
1210                 down instead of into them.
1211         */
1212         v3s16 dirs[10] = {
1213                 v3s16(0,0,1), // back
1214                 v3s16(0,1,0), // top
1215                 v3s16(1,1,0), // topright
1216                 v3s16(-1,1,0), // topleft
1217                 v3s16(0,1,1), // topback
1218                 v3s16(0,1,-1), // topfront
1219                 v3s16(1,0,0), // right
1220                 v3s16(0,0,-1), // front
1221                 v3s16(0,-1,0), // bottom
1222                 v3s16(-1,0,0), // left
1223         };
1224         for(u16 i=0; i<10; i++)
1225         {
1226                 try
1227                 {
1228
1229                 v3s16 p2 = p + dirs[i];
1230
1231                 MapNode n2 = getNode(p2);
1232                 if(content_liquid(n2.d))
1233                 {
1234                         m_transforming_liquid.push_back(p2);
1235                 }
1236
1237                 }catch(InvalidPositionException &e)
1238                 {
1239                 }
1240         }
1241 }
1242
1243 bool Map::addNodeWithEvent(v3s16 p, MapNode n)
1244 {
1245         MapEditEvent event;
1246         event.type = MEET_ADDNODE;
1247         event.p = p;
1248         event.n = n;
1249
1250         bool succeeded = true;
1251         try{
1252                 core::map<v3s16, MapBlock*> modified_blocks;
1253                 addNodeAndUpdate(p, n, modified_blocks);
1254
1255                 // Copy modified_blocks to event
1256                 for(core::map<v3s16, MapBlock*>::Iterator
1257                                 i = modified_blocks.getIterator();
1258                                 i.atEnd()==false; i++)
1259                 {
1260                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1261                 }
1262         }
1263         catch(InvalidPositionException &e){
1264                 succeeded = false;
1265         }
1266
1267         dispatchEvent(&event);
1268
1269         return succeeded;
1270 }
1271
1272 bool Map::removeNodeWithEvent(v3s16 p)
1273 {
1274         MapEditEvent event;
1275         event.type = MEET_REMOVENODE;
1276         event.p = p;
1277
1278         bool succeeded = true;
1279         try{
1280                 core::map<v3s16, MapBlock*> modified_blocks;
1281                 removeNodeAndUpdate(p, modified_blocks);
1282
1283                 // Copy modified_blocks to event
1284                 for(core::map<v3s16, MapBlock*>::Iterator
1285                                 i = modified_blocks.getIterator();
1286                                 i.atEnd()==false; i++)
1287                 {
1288                         event.modified_blocks.insert(i.getNode()->getKey(), false);
1289                 }
1290         }
1291         catch(InvalidPositionException &e){
1292                 succeeded = false;
1293         }
1294
1295         dispatchEvent(&event);
1296
1297         return succeeded;
1298 }
1299
1300 bool Map::dayNightDiffed(v3s16 blockpos)
1301 {
1302         try{
1303                 v3s16 p = blockpos + v3s16(0,0,0);
1304                 MapBlock *b = getBlockNoCreate(p);
1305                 if(b->dayNightDiffed())
1306                         return true;
1307         }
1308         catch(InvalidPositionException &e){}
1309         // Leading edges
1310         try{
1311                 v3s16 p = blockpos + v3s16(-1,0,0);
1312                 MapBlock *b = getBlockNoCreate(p);
1313                 if(b->dayNightDiffed())
1314                         return true;
1315         }
1316         catch(InvalidPositionException &e){}
1317         try{
1318                 v3s16 p = blockpos + v3s16(0,-1,0);
1319                 MapBlock *b = getBlockNoCreate(p);
1320                 if(b->dayNightDiffed())
1321                         return true;
1322         }
1323         catch(InvalidPositionException &e){}
1324         try{
1325                 v3s16 p = blockpos + v3s16(0,0,-1);
1326                 MapBlock *b = getBlockNoCreate(p);
1327                 if(b->dayNightDiffed())
1328                         return true;
1329         }
1330         catch(InvalidPositionException &e){}
1331         // Trailing edges
1332         try{
1333                 v3s16 p = blockpos + v3s16(1,0,0);
1334                 MapBlock *b = getBlockNoCreate(p);
1335                 if(b->dayNightDiffed())
1336                         return true;
1337         }
1338         catch(InvalidPositionException &e){}
1339         try{
1340                 v3s16 p = blockpos + v3s16(0,1,0);
1341                 MapBlock *b = getBlockNoCreate(p);
1342                 if(b->dayNightDiffed())
1343                         return true;
1344         }
1345         catch(InvalidPositionException &e){}
1346         try{
1347                 v3s16 p = blockpos + v3s16(0,0,1);
1348                 MapBlock *b = getBlockNoCreate(p);
1349                 if(b->dayNightDiffed())
1350                         return true;
1351         }
1352         catch(InvalidPositionException &e){}
1353
1354         return false;
1355 }
1356
1357 /*
1358         Updates usage timers
1359 */
1360 void Map::timerUpdate(float dtime)
1361 {
1362         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
1363
1364         core::map<v2s16, MapSector*>::Iterator si;
1365
1366         si = m_sectors.getIterator();
1367         for(; si.atEnd() == false; si++)
1368         {
1369                 MapSector *sector = si.getNode()->getValue();
1370
1371                 core::list<MapBlock*> blocks;
1372                 sector->getBlocks(blocks);
1373                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1374                                 i != blocks.end(); i++)
1375                 {
1376                         (*i)->incrementUsageTimer(dtime);
1377                 }
1378         }
1379 }
1380
1381 void Map::deleteSectors(core::list<v2s16> &list, bool only_blocks)
1382 {
1383         core::list<v2s16>::Iterator j;
1384         for(j=list.begin(); j!=list.end(); j++)
1385         {
1386                 MapSector *sector = m_sectors[*j];
1387                 if(only_blocks)
1388                 {
1389                         sector->deleteBlocks();
1390                 }
1391                 else
1392                 {
1393                         /*
1394                                 If sector is in sector cache, remove it from there
1395                         */
1396                         if(m_sector_cache == sector)
1397                         {
1398                                 m_sector_cache = NULL;
1399                         }
1400                         /*
1401                                 Remove from map and delete
1402                         */
1403                         m_sectors.remove(*j);
1404                         delete sector;
1405                 }
1406         }
1407 }
1408
1409 u32 Map::unloadUnusedData(float timeout, bool only_blocks,
1410                 core::list<v3s16> *deleted_blocks)
1411 {
1412         core::list<v2s16> sector_deletion_queue;
1413
1414         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1415         for(; si.atEnd() == false; si++)
1416         {
1417                 MapSector *sector = si.getNode()->getValue();
1418
1419                 bool all_blocks_deleted = true;
1420
1421                 core::list<MapBlock*> blocks;
1422                 sector->getBlocks(blocks);
1423                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1424                                 i != blocks.end(); i++)
1425                 {
1426                         MapBlock *block = (*i);
1427
1428                         if(block->getUsageTimer() > timeout)
1429                         {
1430                                 // Save if modified
1431                                 if(block->getModified() != MOD_STATE_CLEAN)
1432                                         saveBlock(block);
1433                                 // Unload
1434                                 sector->removeBlock(block);
1435                                 delete block;
1436                         }
1437                         else
1438                         {
1439                                 all_blocks_deleted = false;
1440                         }
1441                 }
1442
1443                 if(all_blocks_deleted)
1444                 {
1445                         sector_deletion_queue.push_back(si.getNode()->getKey());
1446                 }
1447         }
1448
1449 #if 0
1450         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
1451         for(; i.atEnd() == false; i++)
1452         {
1453                 MapSector *sector = i.getNode()->getValue();
1454                 /*
1455                         Delete sector from memory if it hasn't been used in a long time
1456                 */
1457                 if(sector->usage_timer > timeout)
1458                 {
1459                         sector_deletion_queue.push_back(i.getNode()->getKey());
1460
1461                         if(deleted_blocks != NULL)
1462                         {
1463                                 // Collect positions of blocks of sector
1464                                 MapSector *sector = i.getNode()->getValue();
1465                                 core::list<MapBlock*> blocks;
1466                                 sector->getBlocks(blocks);
1467                                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1468                                                 i != blocks.end(); i++)
1469                                 {
1470                                         deleted_blocks->push_back((*i)->getPos());
1471                                 }
1472                         }
1473                 }
1474         }
1475 #endif
1476
1477         deleteSectors(sector_deletion_queue, only_blocks);
1478         return sector_deletion_queue.getSize();
1479 }
1480
1481 void Map::PrintInfo(std::ostream &out)
1482 {
1483         out<<"Map: ";
1484 }
1485
1486 #define WATER_DROP_BOOST 4
1487
1488 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1489 {
1490         DSTACK(__FUNCTION_NAME);
1491         //TimeTaker timer("transformLiquids()");
1492
1493         u32 loopcount = 0;
1494         u32 initial_size = m_transforming_liquid.size();
1495
1496         /*if(initial_size != 0)
1497                 dstream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1498
1499         while(m_transforming_liquid.size() != 0)
1500         {
1501                 /*
1502                         Get a queued transforming liquid node
1503                 */
1504                 v3s16 p0 = m_transforming_liquid.pop_front();
1505
1506                 MapNode n0 = getNode(p0);
1507
1508                 // Don't deal with non-liquids
1509                 if(content_liquid(n0.d) == false)
1510                         continue;
1511
1512                 bool is_source = !content_flowing_liquid(n0.d);
1513
1514                 u8 liquid_level = 8;
1515                 if(is_source == false)
1516                         liquid_level = n0.param2 & 0x0f;
1517
1518                 // Turn possible source into non-source
1519                 u8 nonsource_c = make_liquid_flowing(n0.d);
1520
1521                 // Counts surrounding liquid source blocks
1522                 u8 surrounding_sources = 0;
1523
1524                 /*
1525                         If not source, check that some node flows into this one
1526                         and what is the level of liquid in this one
1527                 */
1528                 if(is_source == false)
1529                 {
1530                         s8 new_liquid_level_max = -1;
1531
1532                         v3s16 dirs_from[5] = {
1533                                 v3s16(0,1,0), // top
1534                                 v3s16(0,0,1), // back
1535                                 v3s16(1,0,0), // right
1536                                 v3s16(0,0,-1), // front
1537                                 v3s16(-1,0,0), // left
1538                         };
1539                         for(u16 i=0; i<5; i++)
1540                         {
1541                                 try
1542                                 {
1543
1544                                 bool from_top = (i==0);
1545
1546                                 v3s16 p2 = p0 + dirs_from[i];
1547                                 MapNode n2 = getNode(p2);
1548
1549                                 if(content_liquid(n2.d))
1550                                 {
1551                                         u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1552                                         // Check that the liquids are the same type
1553                                         if(n2_nonsource_c != nonsource_c)
1554                                         {
1555                                                 dstream<<"WARNING: Not handling: different liquids"
1556                                                                 " collide"<<std::endl;
1557                                                 continue;
1558                                         }
1559                                         bool n2_is_source = !content_flowing_liquid(n2.d);
1560                                         s8 n2_liquid_level = 8;
1561                                         if(n2_is_source)
1562                                                 surrounding_sources++;
1563                                         else
1564                                                 n2_liquid_level = n2.param2 & 0x07;
1565
1566                                         s8 new_liquid_level = -1;
1567                                         if(from_top)
1568                                         {
1569                                                 //new_liquid_level = 7;
1570                                                 if(n2_liquid_level >= 7 - WATER_DROP_BOOST)
1571                                                         new_liquid_level = 7;
1572                                                 else
1573                                                         new_liquid_level = n2_liquid_level + WATER_DROP_BOOST;
1574                                         }
1575                                         else if(n2_liquid_level > 0)
1576                                         {
1577                                                 // If the neighbor node isn't a source and flows downwards,
1578                                                 // it doesn't flow into this node
1579                                                 if (n2_is_source)
1580                                                 {
1581                                                         new_liquid_level = n2_liquid_level - 1;
1582                                                 }
1583                                                 else
1584                                                 {
1585                                                         // Node below n2
1586                                                         MapNode n3 = getNodeNoEx(p2 + v3s16(0,-1,0));
1587                                                         // NOTE: collision of different liquids not yet handled here.
1588                                                         if (content_features(n3.d).liquid_type != LIQUID_FLOWING)
1589                                                         new_liquid_level = n2_liquid_level - 1;
1590                                                 }
1591                                         }
1592
1593                                         if(new_liquid_level > new_liquid_level_max)
1594                                                 new_liquid_level_max = new_liquid_level;
1595                                 }
1596
1597                                 }catch(InvalidPositionException &e)
1598                                 {
1599                                 }
1600                         } //for
1601
1602                         /*
1603                                 If liquid level should be something else, update it and
1604                                 add all the neighboring water nodes to the transform queue.
1605                         */
1606                         if(new_liquid_level_max != liquid_level || (!is_source && surrounding_sources >= 2))
1607                         {
1608                                 if (surrounding_sources >= 2)
1609                                 {
1610                                         n0.d = content_features(n0.d).liquid_alternative_source;
1611                                         setNode(p0,n0);
1612                                 }
1613                                 else if(new_liquid_level_max == -1)
1614                                 {
1615                                         // Remove water alltoghether
1616                                         n0.d = CONTENT_AIR;
1617                                         n0.param2 = 0;
1618                                         setNode(p0, n0);
1619                                 }
1620                                 else
1621                                 {
1622                                         n0.param2 = new_liquid_level_max;
1623                                         liquid_level = new_liquid_level_max;
1624                                         setNode(p0, n0);
1625                                 }
1626
1627                                 // Block has been modified
1628                                 {
1629                                         v3s16 blockpos = getNodeBlockPos(p0);
1630                                         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1631                                         if(block != NULL)
1632                                                 modified_blocks.insert(blockpos, block);
1633                                 }
1634
1635                                 /*
1636                                         Add neighboring non-source liquid nodes to transform queue.
1637                                 */
1638                                 v3s16 dirs[6] = {
1639                                         v3s16(0,0,1), // back
1640                                         v3s16(0,1,0), // top
1641                                         v3s16(1,0,0), // right
1642                                         v3s16(0,0,-1), // front
1643                                         v3s16(0,-1,0), // bottom
1644                                         v3s16(-1,0,0), // left
1645                                 };
1646                                 for(u16 i=0; i<6; i++)
1647                                 {
1648                                         try
1649                                         {
1650
1651                                         v3s16 p2 = p0 + dirs[i];
1652
1653                                         MapNode n2 = getNode(p2);
1654                                         if(content_flowing_liquid(n2.d))
1655                                         {
1656                                                 m_transforming_liquid.push_back(p2);
1657                                         }
1658
1659                                         }catch(InvalidPositionException &e)
1660                                         {
1661                                         }
1662                                 }
1663                         }
1664                 }
1665
1666                 // Get a new one from queue if the node has turned into non-water
1667                 if(content_liquid(n0.d) == false)
1668                         continue;
1669
1670                 /*
1671                         Flow water from this node
1672                 */
1673                 v3s16 dirs_to[5] = {
1674                         v3s16(0,-1,0), // bottom
1675                         v3s16(0,0,1), // back
1676                         v3s16(1,0,0), // right
1677                         v3s16(0,0,-1), // front
1678                         v3s16(-1,0,0), // left
1679                 };
1680                 for(u16 i=0; i<5; i++)
1681                 {
1682                         try
1683                         {
1684
1685                         bool to_bottom = (i == 0);
1686
1687                         // If liquid is at lowest possible height, it's not going
1688                         // anywhere except down
1689                         if(liquid_level == 0 && to_bottom == false)
1690                                 continue;
1691
1692                         u8 liquid_next_level = 0;
1693                         // If going to bottom
1694                         if(to_bottom)
1695                         {
1696                                 //liquid_next_level = 7;
1697                                 if(liquid_level >= 7 - WATER_DROP_BOOST)
1698                                         liquid_next_level = 7;
1699                                 else
1700                                         liquid_next_level = liquid_level + WATER_DROP_BOOST;
1701                         }
1702                         else
1703                                 liquid_next_level = liquid_level - 1;
1704
1705                         bool n2_changed = false;
1706                         bool flowed = false;
1707
1708                         v3s16 p2 = p0 + dirs_to[i];
1709
1710                         MapNode n2 = getNode(p2);
1711                         //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
1712
1713                         if(content_liquid(n2.d))
1714                         {
1715                                 u8 n2_nonsource_c = make_liquid_flowing(n2.d);
1716                                 // Check that the liquids are the same type
1717                                 if(n2_nonsource_c != nonsource_c)
1718                                 {
1719                                         dstream<<"WARNING: Not handling: different liquids"
1720                                                         " collide"<<std::endl;
1721                                         continue;
1722                                 }
1723                                 bool n2_is_source = !content_flowing_liquid(n2.d);
1724                                 u8 n2_liquid_level = 8;
1725                                 if(n2_is_source == false)
1726                                         n2_liquid_level = n2.param2 & 0x07;
1727
1728                                 if(to_bottom)
1729                                 {
1730                                         flowed = true;
1731                                 }
1732
1733                                 if(n2_is_source)
1734                                 {
1735                                         // Just flow into the source, nothing changes.
1736                                         // n2_changed is not set because destination didn't change
1737                                         flowed = true;
1738                                 }
1739                                 else
1740                                 {
1741                                         if(liquid_next_level > n2_liquid_level)
1742                                         {
1743                                                 n2.param2 = liquid_next_level;
1744                                                 setNode(p2, n2);
1745
1746                                                 n2_changed = true;
1747                                                 flowed = true;
1748                                         }
1749                                 }
1750                         }
1751                         else if(n2.d == CONTENT_AIR)
1752                         {
1753                                 n2.d = nonsource_c;
1754                                 n2.param2 = liquid_next_level;
1755                                 setNode(p2, n2);
1756
1757                                 n2_changed = true;
1758                                 flowed = true;
1759                         }
1760
1761                         //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl;
1762
1763                         if(n2_changed)
1764                         {
1765                                 m_transforming_liquid.push_back(p2);
1766
1767                                 v3s16 blockpos = getNodeBlockPos(p2);
1768                                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1769                                 if(block != NULL)
1770                                         modified_blocks.insert(blockpos, block);
1771                         }
1772
1773                         // If n2_changed to bottom, don't flow anywhere else
1774                         if(to_bottom && flowed && !is_source)
1775                                 break;
1776
1777                         }catch(InvalidPositionException &e)
1778                         {
1779                         }
1780                 }
1781
1782                 loopcount++;
1783                 //if(loopcount >= 100000)
1784                 if(loopcount >= initial_size * 1)
1785                         break;
1786         }
1787         //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1788 }
1789
1790 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1791 {
1792         v3s16 blockpos = getNodeBlockPos(p);
1793         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1794         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1795         if(block == NULL)
1796         {
1797                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1798                                 <<std::endl;
1799                 return NULL;
1800         }
1801         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1802         return meta;
1803 }
1804
1805 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1806 {
1807         v3s16 blockpos = getNodeBlockPos(p);
1808         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1809         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1810         if(block == NULL)
1811         {
1812                 dstream<<"WARNING: Map::setNodeMetadata(): Block not found"
1813                                 <<std::endl;
1814                 return;
1815         }
1816         block->m_node_metadata.set(p_rel, meta);
1817 }
1818
1819 void Map::removeNodeMetadata(v3s16 p)
1820 {
1821         v3s16 blockpos = getNodeBlockPos(p);
1822         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1823         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1824         if(block == NULL)
1825         {
1826                 dstream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1827                                 <<std::endl;
1828                 return;
1829         }
1830         block->m_node_metadata.remove(p_rel);
1831 }
1832
1833 void Map::nodeMetadataStep(float dtime,
1834                 core::map<v3s16, MapBlock*> &changed_blocks)
1835 {
1836         /*
1837                 NOTE:
1838                 Currently there is no way to ensure that all the necessary
1839                 blocks are loaded when this is run. (They might get unloaded)
1840                 NOTE: ^- Actually, that might not be so. In a quick test it
1841                 reloaded a block with a furnace when I walked back to it from
1842                 a distance.
1843         */
1844         core::map<v2s16, MapSector*>::Iterator si;
1845         si = m_sectors.getIterator();
1846         for(; si.atEnd() == false; si++)
1847         {
1848                 MapSector *sector = si.getNode()->getValue();
1849                 core::list< MapBlock * > sectorblocks;
1850                 sector->getBlocks(sectorblocks);
1851                 core::list< MapBlock * >::Iterator i;
1852                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1853                 {
1854                         MapBlock *block = *i;
1855                         bool changed = block->m_node_metadata.step(dtime);
1856                         if(changed)
1857                                 changed_blocks[block->getPos()] = block;
1858                 }
1859         }
1860 }
1861
1862 /*
1863         ServerMap
1864 */
1865
1866 ServerMap::ServerMap(std::string savedir):
1867         Map(dout_server),
1868         m_seed(0),
1869         m_map_metadata_changed(true)
1870 {
1871         dstream<<__FUNCTION_NAME<<std::endl;
1872
1873         //m_chunksize = 8; // Takes a few seconds
1874
1875         m_seed = (((u64)(myrand()%0xffff)<<0)
1876                         + ((u64)(myrand()%0xffff)<<16)
1877                         + ((u64)(myrand()%0xffff)<<32)
1878                         + ((u64)(myrand()%0xffff)<<48));
1879
1880         /*
1881                 Experimental and debug stuff
1882         */
1883
1884         {
1885         }
1886
1887         /*
1888                 Try to load map; if not found, create a new one.
1889         */
1890
1891         m_savedir = savedir;
1892         m_map_saving_enabled = false;
1893
1894         try
1895         {
1896                 // If directory exists, check contents and load if possible
1897                 if(fs::PathExists(m_savedir))
1898                 {
1899                         // If directory is empty, it is safe to save into it.
1900                         if(fs::GetDirListing(m_savedir).size() == 0)
1901                         {
1902                                 dstream<<DTIME<<"Server: Empty save directory is valid."
1903                                                 <<std::endl;
1904                                 m_map_saving_enabled = true;
1905                         }
1906                         else
1907                         {
1908                                 try{
1909                                         // Load map metadata (seed, chunksize)
1910                                         loadMapMeta();
1911                                 }
1912                                 catch(FileNotGoodException &e){
1913                                         dstream<<DTIME<<"WARNING: Could not load map metadata"
1914                                                         //<<" Disabling chunk-based generator."
1915                                                         <<std::endl;
1916                                         //m_chunksize = 0;
1917                                 }
1918
1919                                 /*try{
1920                                         // Load chunk metadata
1921                                         loadChunkMeta();
1922                                 }
1923                                 catch(FileNotGoodException &e){
1924                                         dstream<<DTIME<<"WARNING: Could not load chunk metadata."
1925                                                         <<" Disabling chunk-based generator."
1926                                                         <<std::endl;
1927                                         m_chunksize = 0;
1928                                 }*/
1929
1930                                 /*dstream<<DTIME<<"Server: Successfully loaded chunk "
1931                                                 "metadata and sector (0,0) from "<<savedir<<
1932                                                 ", assuming valid save directory."
1933                                                 <<std::endl;*/
1934
1935                                 dstream<<DTIME<<"INFO: Server: Successfully loaded map "
1936                                                 <<"and chunk metadata from "<<savedir
1937                                                 <<", assuming valid save directory."
1938                                                 <<std::endl;
1939
1940                                 m_map_saving_enabled = true;
1941                                 // Map loaded, not creating new one
1942                                 return;
1943                         }
1944                 }
1945                 // If directory doesn't exist, it is safe to save to it
1946                 else{
1947                         m_map_saving_enabled = true;
1948                 }
1949         }
1950         catch(std::exception &e)
1951         {
1952                 dstream<<DTIME<<"WARNING: Server: Failed to load map from "<<savedir
1953                                 <<", exception: "<<e.what()<<std::endl;
1954                 dstream<<"Please remove the map or fix it."<<std::endl;
1955                 dstream<<"WARNING: Map saving will be disabled."<<std::endl;
1956         }
1957
1958         dstream<<DTIME<<"INFO: Initializing new map."<<std::endl;
1959
1960         // Create zero sector
1961         emergeSector(v2s16(0,0));
1962
1963         // Initially write whole map
1964         save(false);
1965 }
1966
1967 ServerMap::~ServerMap()
1968 {
1969         dstream<<__FUNCTION_NAME<<std::endl;
1970
1971         try
1972         {
1973                 if(m_map_saving_enabled)
1974                 {
1975                         //save(false);
1976                         // Save only changed parts
1977                         save(true);
1978                         dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
1979                 }
1980                 else
1981                 {
1982                         dstream<<DTIME<<"Server: map not saved"<<std::endl;
1983                 }
1984         }
1985         catch(std::exception &e)
1986         {
1987                 dstream<<DTIME<<"Server: Failed to save map to "<<m_savedir
1988                                 <<", exception: "<<e.what()<<std::endl;
1989         }
1990
1991 #if 0
1992         /*
1993                 Free all MapChunks
1994         */
1995         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
1996         for(; i.atEnd() == false; i++)
1997         {
1998                 MapChunk *chunk = i.getNode()->getValue();
1999                 delete chunk;
2000         }
2001 #endif
2002 }
2003
2004 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2005 {
2006         /*dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2007                         <<blockpos.Z<<")"<<std::endl;*/
2008
2009         data->no_op = false;
2010         data->seed = m_seed;
2011         data->blockpos = blockpos;
2012
2013         /*
2014                 Create the whole area of this and the neighboring blocks
2015         */
2016         {
2017                 //TimeTaker timer("initBlockMake() create area");
2018                 
2019                 for(s16 x=-1; x<=1; x++)
2020                 for(s16 z=-1; z<=1; z++)
2021                 {
2022                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2023                         // Sector metadata is loaded from disk if not already loaded.
2024                         ServerMapSector *sector = createSector(sectorpos);
2025                         assert(sector);
2026
2027                         for(s16 y=-1; y<=1; y++)
2028                         {
2029                                 MapBlock *block = createBlock(blockpos);
2030
2031                                 // Lighting won't be calculated
2032                                 block->setLightingExpired(true);
2033                                 // Lighting will be calculated
2034                                 //block->setLightingExpired(false);
2035
2036                                 /*
2037                                         Block gets sunlight if this is true.
2038
2039                                         This should be set to true when the top side of a block
2040                                         is completely exposed to the sky.
2041                                 */
2042                                 block->setIsUnderground(false);
2043                         }
2044                 }
2045         }
2046         
2047         /*
2048                 Now we have a big empty area.
2049
2050                 Make a ManualMapVoxelManipulator that contains this and the
2051                 neighboring blocks
2052         */
2053         
2054         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2055         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2056         
2057         data->vmanip = new ManualMapVoxelManipulator(this);
2058         //data->vmanip->setMap(this);
2059
2060         // Add the area
2061         {
2062                 //TimeTaker timer("initBlockMake() initialEmerge");
2063                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2064         }
2065
2066         // Data is ready now.
2067 }
2068
2069 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2070                 core::map<v3s16, MapBlock*> &changed_blocks)
2071 {
2072         v3s16 blockpos = data->blockpos;
2073         /*dstream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2074                         <<blockpos.Z<<")"<<std::endl;*/
2075
2076         if(data->no_op)
2077         {
2078                 dstream<<"finishBlockMake(): no-op"<<std::endl;
2079                 return NULL;
2080         }
2081
2082         /*dstream<<"Resulting vmanip:"<<std::endl;
2083         data->vmanip.print(dstream);*/
2084         
2085         /*
2086                 Blit generated stuff to map
2087                 NOTE: blitBackAll adds nearly everything to changed_blocks
2088         */
2089         {
2090                 // 70ms @cs=8
2091                 //TimeTaker timer("finishBlockMake() blitBackAll");
2092                 data->vmanip->blitBackAll(&changed_blocks);
2093         }
2094 #if 1
2095         dstream<<"finishBlockMake: changed_blocks.size()="
2096                         <<changed_blocks.size()<<std::endl;
2097 #endif
2098         /*
2099                 Copy transforming liquid information
2100         */
2101         while(data->transforming_liquid.size() > 0)
2102         {
2103                 v3s16 p = data->transforming_liquid.pop_front();
2104                 m_transforming_liquid.push_back(p);
2105         }
2106         
2107         /*
2108                 Get central block
2109         */
2110         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2111         assert(block);
2112
2113         /*
2114                 Set is_underground flag for lighting with sunlight
2115         */
2116
2117         block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2118
2119         /*
2120                 Add sunlight to central block.
2121                 This makes in-dark-spawning monsters to not flood the whole thing.
2122                 Do not spread the light, though.
2123         */
2124         /*core::map<v3s16, bool> light_sources;
2125         bool black_air_left = false;
2126         block->propagateSunlight(light_sources, true, &black_air_left);*/
2127
2128         /*
2129                 NOTE: Lighting and object adding shouldn't really be here, but
2130                 lighting is a bit tricky to move properly to makeBlock.
2131                 TODO: Do this the right way anyway.
2132         */
2133
2134         /*
2135                 Update lighting
2136         */
2137
2138         core::map<v3s16, MapBlock*> lighting_update_blocks;
2139         // Center block
2140         lighting_update_blocks.insert(block->getPos(), block);
2141 #if 0
2142         // All modified blocks
2143         for(core::map<v3s16, MapBlock*>::Iterator
2144                         i = changed_blocks.getIterator();
2145                         i.atEnd() == false; i++)
2146         {
2147                 lighting_update_blocks.insert(i.getNode()->getKey(),
2148                                 i.getNode()->getValue());
2149         }
2150 #endif
2151         updateLighting(lighting_update_blocks, changed_blocks);
2152         
2153         /*
2154                 Add random objects to block
2155         */
2156         mapgen::add_random_objects(block);
2157
2158         /*
2159                 Go through changed blocks
2160         */
2161         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2162                         i.atEnd() == false; i++)
2163         {
2164                 MapBlock *block = i.getNode()->getValue();
2165                 assert(block);
2166                 /*
2167                         Update day/night difference cache of the MapBlocks
2168                 */
2169                 block->updateDayNightDiff();
2170                 /*
2171                         Set block as modified
2172                 */
2173                 block->raiseModified(MOD_STATE_WRITE_NEEDED);
2174         }
2175
2176         /*
2177                 Set central block as generated
2178         */
2179         block->setGenerated(true);
2180         
2181         /*
2182                 Save changed parts of map
2183                 NOTE: Will be saved later.
2184         */
2185         //save(true);
2186
2187         /*dstream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2188                         <<blockpos.Z<<")"<<std::endl;*/
2189         
2190         return block;
2191 }
2192
2193 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2194 {
2195         DSTACKF("%s: p2d=(%d,%d)",
2196                         __FUNCTION_NAME,
2197                         p2d.X, p2d.Y);
2198         
2199         /*
2200                 Check if it exists already in memory
2201         */
2202         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2203         if(sector != NULL)
2204                 return sector;
2205         
2206         /*
2207                 Try to load it from disk (with blocks)
2208         */
2209         //if(loadSectorFull(p2d) == true)
2210
2211         /*
2212                 Try to load metadata from disk
2213         */
2214         if(loadSectorMeta(p2d) == true)
2215         {
2216                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2217                 if(sector == NULL)
2218                 {
2219                         dstream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2220                         throw InvalidPositionException("");
2221                 }
2222                 return sector;
2223         }
2224
2225         /*
2226                 Do not create over-limit
2227         */
2228         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2229         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2230         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2231         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2232                 throw InvalidPositionException("createSector(): pos. over limit");
2233
2234         /*
2235                 Generate blank sector
2236         */
2237         
2238         sector = new ServerMapSector(this, p2d);
2239         
2240         // Sector position on map in nodes
2241         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2242
2243         /*
2244                 Insert to container
2245         */
2246         m_sectors.insert(p2d, sector);
2247         
2248         return sector;
2249 }
2250
2251 /*
2252         This is a quick-hand function for calling makeBlock().
2253 */
2254 MapBlock * ServerMap::generateBlock(
2255                 v3s16 p,
2256                 core::map<v3s16, MapBlock*> &modified_blocks
2257 )
2258 {
2259         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2260         
2261         /*dstream<<"generateBlock(): "
2262                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2263                         <<std::endl;*/
2264         
2265         TimeTaker timer("generateBlock");
2266         
2267         //MapBlock *block = original_dummy;
2268                         
2269         v2s16 p2d(p.X, p.Z);
2270         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2271         
2272         /*
2273                 Do not generate over-limit
2274         */
2275         if(blockpos_over_limit(p))
2276         {
2277                 dstream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2278                 throw InvalidPositionException("generateBlock(): pos. over limit");
2279         }
2280
2281         /*
2282                 Create block make data
2283         */
2284         mapgen::BlockMakeData data;
2285         initBlockMake(&data, p);
2286
2287         /*
2288                 Generate block
2289         */
2290         {
2291                 TimeTaker t("mapgen::make_block()");
2292                 mapgen::make_block(&data);
2293         }
2294
2295         /*
2296                 Blit data back on map, update lighting, add mobs and whatever this does
2297         */
2298         finishBlockMake(&data, modified_blocks);
2299
2300         /*
2301                 Get central block
2302         */
2303         MapBlock *block = getBlockNoCreateNoEx(p);
2304         assert(block);
2305
2306 #if 0
2307         /*
2308                 Check result
2309         */
2310         bool erroneus_content = false;
2311         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2312         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2313         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2314         {
2315                 v3s16 p(x0,y0,z0);
2316                 MapNode n = block->getNode(p);
2317                 if(n.d == CONTENT_IGNORE)
2318                 {
2319                         dstream<<"CONTENT_IGNORE at "
2320                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2321                                         <<std::endl;
2322                         erroneus_content = true;
2323                         assert(0);
2324                 }
2325         }
2326         if(erroneus_content)
2327         {
2328                 assert(0);
2329         }
2330 #endif
2331
2332 #if 0
2333         /*
2334                 Generate a completely empty block
2335         */
2336         for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2337         for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2338         {
2339                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2340                 {
2341                         MapNode n;
2342                         if(y0%2==0)
2343                                 n.d = CONTENT_AIR;
2344                         else
2345                                 n.d = CONTENT_STONE;
2346                         block->setNode(v3s16(x0,y0,z0), n);
2347                 }
2348         }
2349 #endif
2350
2351         return block;
2352 }
2353
2354 MapBlock * ServerMap::createBlock(v3s16 p)
2355 {
2356         DSTACKF("%s: p=(%d,%d,%d)",
2357                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2358         
2359         /*
2360                 Do not create over-limit
2361         */
2362         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2363         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2364         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2365         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2366         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2367         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2368                 throw InvalidPositionException("createBlock(): pos. over limit");
2369         
2370         v2s16 p2d(p.X, p.Z);
2371         s16 block_y = p.Y;
2372         /*
2373                 This will create or load a sector if not found in memory.
2374                 If block exists on disk, it will be loaded.
2375
2376                 NOTE: On old save formats, this will be slow, as it generates
2377                       lighting on blocks for them.
2378         */
2379         ServerMapSector *sector;
2380         try{
2381                 sector = (ServerMapSector*)createSector(p2d);
2382                 assert(sector->getId() == MAPSECTOR_SERVER);
2383         }
2384         catch(InvalidPositionException &e)
2385         {
2386                 dstream<<"createBlock: createSector() failed"<<std::endl;
2387                 throw e;
2388         }
2389         /*
2390                 NOTE: This should not be done, or at least the exception
2391                 should not be passed on as std::exception, because it
2392                 won't be catched at all.
2393         */
2394         /*catch(std::exception &e)
2395         {
2396                 dstream<<"createBlock: createSector() failed: "
2397                                 <<e.what()<<std::endl;
2398                 throw e;
2399         }*/
2400
2401         /*
2402                 Try to get a block from the sector
2403         */
2404
2405         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2406         if(block)
2407         {
2408                 if(block->isDummy())
2409                         block->unDummify();
2410                 return block;
2411         }
2412         // Create blank
2413         block = sector->createBlankBlock(block_y);
2414         return block;
2415 }
2416
2417 #if 0
2418 MapBlock * ServerMap::emergeBlock(
2419                 v3s16 p,
2420                 bool only_from_disk,
2421                 core::map<v3s16, MapBlock*> &changed_blocks,
2422                 core::map<v3s16, MapBlock*> &lighting_invalidated_blocks
2423 )
2424 {
2425         DSTACKF("%s: p=(%d,%d,%d), only_from_disk=%d",
2426                         __FUNCTION_NAME,
2427                         p.X, p.Y, p.Z, only_from_disk);
2428         
2429         // This has to be redone or removed
2430         assert(0);
2431         return NULL;
2432 }
2433 #endif
2434
2435 #if 0
2436         /*
2437                 Do not generate over-limit
2438         */
2439         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2440         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2441         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2442         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2443         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2444         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2445                 throw InvalidPositionException("emergeBlock(): pos. over limit");
2446         
2447         v2s16 p2d(p.X, p.Z);
2448         s16 block_y = p.Y;
2449         /*
2450                 This will create or load a sector if not found in memory.
2451                 If block exists on disk, it will be loaded.
2452         */
2453         ServerMapSector *sector;
2454         try{
2455                 sector = createSector(p2d);
2456                 //sector = emergeSector(p2d, changed_blocks);
2457         }
2458         catch(InvalidPositionException &e)
2459         {
2460                 dstream<<"emergeBlock: createSector() failed: "
2461                                 <<e.what()<<std::endl;
2462                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2463                                 <<std::endl
2464                                 <<"You could try to delete it."<<std::endl;
2465                 throw e;
2466         }
2467         catch(VersionMismatchException &e)
2468         {
2469                 dstream<<"emergeBlock: createSector() failed: "
2470                                 <<e.what()<<std::endl;
2471                 dstream<<"Path to failed sector: "<<getSectorDir(p2d)
2472                                 <<std::endl
2473                                 <<"You could try to delete it."<<std::endl;
2474                 throw e;
2475         }
2476
2477         /*
2478                 Try to get a block from the sector
2479         */
2480
2481         bool does_not_exist = false;
2482         bool lighting_expired = false;
2483         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2484         
2485         // If not found, try loading from disk
2486         if(block == NULL)
2487         {
2488                 block = loadBlock(p);
2489         }
2490         
2491         // Handle result
2492         if(block == NULL)
2493         {
2494                 does_not_exist = true;
2495         }
2496         else if(block->isDummy() == true)
2497         {
2498                 does_not_exist = true;
2499         }
2500         else if(block->getLightingExpired())
2501         {
2502                 lighting_expired = true;
2503         }
2504         else
2505         {
2506                 // Valid block
2507                 //dstream<<"emergeBlock(): Returning already valid block"<<std::endl;
2508                 return block;
2509         }
2510         
2511         /*
2512                 If block was not found on disk and not going to generate a
2513                 new one, make sure there is a dummy block in place.
2514         */
2515         if(only_from_disk && (does_not_exist || lighting_expired))
2516         {
2517                 //dstream<<"emergeBlock(): Was not on disk but not generating"<<std::endl;
2518
2519                 if(block == NULL)
2520                 {
2521                         // Create dummy block
2522                         block = new MapBlock(this, p, true);
2523
2524                         // Add block to sector
2525                         sector->insertBlock(block);
2526                 }
2527                 // Done.
2528                 return block;
2529         }
2530
2531         //dstream<<"Not found on disk, generating."<<std::endl;
2532         // 0ms
2533         //TimeTaker("emergeBlock() generate");
2534
2535         //dstream<<"emergeBlock(): Didn't find valid block -> making one"<<std::endl;
2536
2537         /*
2538                 If the block doesn't exist, generate the block.
2539         */
2540         if(does_not_exist)
2541         {
2542                 block = generateBlock(p, block, sector, changed_blocks,
2543                                 lighting_invalidated_blocks); 
2544         }
2545
2546         if(lighting_expired)
2547         {
2548                 lighting_invalidated_blocks.insert(p, block);
2549         }
2550
2551 #if 0
2552         /*
2553                 Initially update sunlight
2554         */
2555         {
2556                 core::map<v3s16, bool> light_sources;
2557                 bool black_air_left = false;
2558                 bool bottom_invalid =
2559                                 block->propagateSunlight(light_sources, true,
2560                                 &black_air_left);
2561
2562                 // If sunlight didn't reach everywhere and part of block is
2563                 // above ground, lighting has to be properly updated
2564                 //if(black_air_left && some_part_underground)
2565                 if(black_air_left)
2566                 {
2567                         lighting_invalidated_blocks[block->getPos()] = block;
2568                 }
2569
2570                 if(bottom_invalid)
2571                 {
2572                         lighting_invalidated_blocks[block->getPos()] = block;
2573                 }
2574         }
2575 #endif
2576         
2577         return block;
2578 }
2579 #endif
2580
2581 s16 ServerMap::findGroundLevel(v2s16 p2d)
2582 {
2583 #if 0
2584         /*
2585                 Uh, just do something random...
2586         */
2587         // Find existing map from top to down
2588         s16 max=63;
2589         s16 min=-64;
2590         v3s16 p(p2d.X, max, p2d.Y);
2591         for(; p.Y>min; p.Y--)
2592         {
2593                 MapNode n = getNodeNoEx(p);
2594                 if(n.d != CONTENT_IGNORE)
2595                         break;
2596         }
2597         if(p.Y == min)
2598                 goto plan_b;
2599         // If this node is not air, go to plan b
2600         if(getNodeNoEx(p).d != CONTENT_AIR)
2601                 goto plan_b;
2602         // Search existing walkable and return it
2603         for(; p.Y>min; p.Y--)
2604         {
2605                 MapNode n = getNodeNoEx(p);
2606                 if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
2607                         return p.Y;
2608         }
2609
2610         // Move to plan b
2611 plan_b:
2612 #endif
2613
2614         /*
2615                 Determine from map generator noise functions
2616         */
2617         
2618         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2619         return level;
2620
2621         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2622         //return (s16)level;
2623 }
2624
2625 void ServerMap::createDirs(std::string path)
2626 {
2627         if(fs::CreateAllDirs(path) == false)
2628         {
2629                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2630                                 <<"\""<<path<<"\""<<std::endl;
2631                 throw BaseException("ServerMap failed to create directory");
2632         }
2633 }
2634
2635 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2636 {
2637         char cc[9];
2638         switch(layout)
2639         {
2640                 case 1:
2641                         snprintf(cc, 9, "%.4x%.4x",
2642                                 (unsigned int)pos.X&0xffff,
2643                                 (unsigned int)pos.Y&0xffff);
2644
2645                         return m_savedir + "/sectors/" + cc;
2646                 case 2:
2647                         snprintf(cc, 9, "%.3x/%.3x",
2648                                 (unsigned int)pos.X&0xfff,
2649                                 (unsigned int)pos.Y&0xfff);
2650
2651                         return m_savedir + "/sectors2/" + cc;
2652                 default:
2653                         assert(false);
2654         }
2655 }
2656
2657 v2s16 ServerMap::getSectorPos(std::string dirname)
2658 {
2659         unsigned int x, y;
2660         int r;
2661         size_t spos = dirname.rfind('/') + 1;
2662         assert(spos != std::string::npos);
2663         if(dirname.size() - spos == 8)
2664         {
2665                 // Old layout
2666                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2667         }
2668         else if(dirname.size() - spos == 3)
2669         {
2670                 // New layout
2671                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x/%3x", &x, &y);
2672                 // Sign-extend the 12 bit values up to 16 bits...
2673                 if(x&0x800) x|=0xF000;
2674                 if(y&0x800) y|=0xF000;
2675         }
2676         else
2677         {
2678                 assert(false);
2679         }
2680         assert(r == 2);
2681         v2s16 pos((s16)x, (s16)y);
2682         return pos;
2683 }
2684
2685 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2686 {
2687         v2s16 p2d = getSectorPos(sectordir);
2688
2689         if(blockfile.size() != 4){
2690                 throw InvalidFilenameException("Invalid block filename");
2691         }
2692         unsigned int y;
2693         int r = sscanf(blockfile.c_str(), "%4x", &y);
2694         if(r != 1)
2695                 throw InvalidFilenameException("Invalid block filename");
2696         return v3s16(p2d.X, y, p2d.Y);
2697 }
2698
2699 std::string ServerMap::getBlockFilename(v3s16 p)
2700 {
2701         char cc[5];
2702         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2703         return cc;
2704 }
2705
2706 void ServerMap::save(bool only_changed)
2707 {
2708         DSTACK(__FUNCTION_NAME);
2709         if(m_map_saving_enabled == false)
2710         {
2711                 dstream<<DTIME<<"WARNING: Not saving map, saving disabled."<<std::endl;
2712                 return;
2713         }
2714         
2715         if(only_changed == false)
2716                 dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
2717                                 <<std::endl;
2718         
2719         if(only_changed == false || m_map_metadata_changed)
2720         {
2721                 saveMapMeta();
2722         }
2723
2724         u32 sector_meta_count = 0;
2725         u32 block_count = 0;
2726         u32 block_count_all = 0; // Number of blocks in memory
2727         
2728         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2729         for(; i.atEnd() == false; i++)
2730         {
2731                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2732                 assert(sector->getId() == MAPSECTOR_SERVER);
2733         
2734                 if(sector->differs_from_disk || only_changed == false)
2735                 {
2736                         saveSectorMeta(sector);
2737                         sector_meta_count++;
2738                 }
2739                 core::list<MapBlock*> blocks;
2740                 sector->getBlocks(blocks);
2741                 core::list<MapBlock*>::Iterator j;
2742                 for(j=blocks.begin(); j!=blocks.end(); j++)
2743                 {
2744                         MapBlock *block = *j;
2745                         
2746                         block_count_all++;
2747
2748                         if(block->getModified() >= MOD_STATE_WRITE_NEEDED 
2749                                         || only_changed == false)
2750                         {
2751                                 saveBlock(block);
2752                                 block_count++;
2753
2754                                 /*dstream<<"ServerMap: Written block ("
2755                                                 <<block->getPos().X<<","
2756                                                 <<block->getPos().Y<<","
2757                                                 <<block->getPos().Z<<")"
2758                                                 <<std::endl;*/
2759                         }
2760                 }
2761         }
2762
2763         /*
2764                 Only print if something happened or saved whole map
2765         */
2766         if(only_changed == false || sector_meta_count != 0
2767                         || block_count != 0)
2768         {
2769                 dstream<<DTIME<<"ServerMap: Written: "
2770                                 <<sector_meta_count<<" sector metadata files, "
2771                                 <<block_count<<" block files"
2772                                 <<", "<<block_count_all<<" blocks in memory."
2773                                 <<std::endl;
2774         }
2775 }
2776
2777 void ServerMap::saveMapMeta()
2778 {
2779         DSTACK(__FUNCTION_NAME);
2780         
2781         dstream<<"INFO: ServerMap::saveMapMeta(): "
2782                         <<"seed="<<m_seed
2783                         <<std::endl;
2784
2785         createDirs(m_savedir);
2786         
2787         std::string fullpath = m_savedir + "/map_meta.txt";
2788         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
2789         if(os.good() == false)
2790         {
2791                 dstream<<"ERROR: ServerMap::saveMapMeta(): "
2792                                 <<"could not open"<<fullpath<<std::endl;
2793                 throw FileNotGoodException("Cannot open chunk metadata");
2794         }
2795         
2796         Settings params;
2797         params.setU64("seed", m_seed);
2798
2799         params.writeLines(os);
2800
2801         os<<"[end_of_params]\n";
2802         
2803         m_map_metadata_changed = false;
2804 }
2805
2806 void ServerMap::loadMapMeta()
2807 {
2808         DSTACK(__FUNCTION_NAME);
2809         
2810         dstream<<"INFO: ServerMap::loadMapMeta(): Loading map metadata"
2811                         <<std::endl;
2812
2813         std::string fullpath = m_savedir + "/map_meta.txt";
2814         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2815         if(is.good() == false)
2816         {
2817                 dstream<<"ERROR: ServerMap::loadMapMeta(): "
2818                                 <<"could not open"<<fullpath<<std::endl;
2819                 throw FileNotGoodException("Cannot open map metadata");
2820         }
2821
2822         Settings params;
2823
2824         for(;;)
2825         {
2826                 if(is.eof())
2827                         throw SerializationError
2828                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
2829                 std::string line;
2830                 std::getline(is, line);
2831                 std::string trimmedline = trim(line);
2832                 if(trimmedline == "[end_of_params]")
2833                         break;
2834                 params.parseConfigLine(line);
2835         }
2836
2837         m_seed = params.getU64("seed");
2838
2839         dstream<<"INFO: ServerMap::loadMapMeta(): "
2840                         <<"seed="<<m_seed
2841                         <<std::endl;
2842 }
2843
2844 void ServerMap::saveSectorMeta(ServerMapSector *sector)
2845 {
2846         DSTACK(__FUNCTION_NAME);
2847         // Format used for writing
2848         u8 version = SER_FMT_VER_HIGHEST;
2849         // Get destination
2850         v2s16 pos = sector->getPos();
2851         std::string dir = getSectorDir(pos);
2852         createDirs(dir);
2853         
2854         std::string fullpath = dir + "/meta";
2855         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
2856         if(o.good() == false)
2857                 throw FileNotGoodException("Cannot open sector metafile");
2858
2859         sector->serialize(o, version);
2860         
2861         sector->differs_from_disk = false;
2862 }
2863
2864 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
2865 {
2866         DSTACK(__FUNCTION_NAME);
2867         // Get destination
2868         v2s16 p2d = getSectorPos(sectordir);
2869
2870         ServerMapSector *sector = NULL;
2871
2872         std::string fullpath = sectordir + "/meta";
2873         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
2874         if(is.good() == false)
2875         {
2876                 // If the directory exists anyway, it probably is in some old
2877                 // format. Just go ahead and create the sector.
2878                 if(fs::PathExists(sectordir))
2879                 {
2880                         dstream<<"ServerMap::loadSectorMeta(): Sector metafile "
2881                                         <<fullpath<<" doesn't exist but directory does."
2882                                         <<" Continuing with a sector with no metadata."
2883                                         <<std::endl;
2884                         sector = new ServerMapSector(this, p2d);
2885                         m_sectors.insert(p2d, sector);
2886                 }
2887                 else
2888                 {
2889                         throw FileNotGoodException("Cannot open sector metafile");
2890                 }
2891         }
2892         else
2893         {
2894                 sector = ServerMapSector::deSerialize
2895                                 (is, this, p2d, m_sectors);
2896                 if(save_after_load)
2897                         saveSectorMeta(sector);
2898         }
2899         
2900         sector->differs_from_disk = false;
2901
2902         return sector;
2903 }
2904
2905 bool ServerMap::loadSectorMeta(v2s16 p2d)
2906 {
2907         DSTACK(__FUNCTION_NAME);
2908
2909         MapSector *sector = NULL;
2910
2911         // The directory layout we're going to load from.
2912         //  1 - original sectors/xxxxzzzz/
2913         //  2 - new sectors2/xxx/zzz/
2914         //  If we load from anything but the latest structure, we will
2915         //  immediately save to the new one, and remove the old.
2916         int loadlayout = 1;
2917         std::string sectordir1 = getSectorDir(p2d, 1);
2918         std::string sectordir;
2919         if(fs::PathExists(sectordir1))
2920         {
2921                 sectordir = sectordir1;
2922         }
2923         else
2924         {
2925                 loadlayout = 2;
2926                 sectordir = getSectorDir(p2d, 2);
2927         }
2928
2929         try{
2930                 sector = loadSectorMeta(sectordir, loadlayout != 2);
2931         }
2932         catch(InvalidFilenameException &e)
2933         {
2934                 return false;
2935         }
2936         catch(FileNotGoodException &e)
2937         {
2938                 return false;
2939         }
2940         catch(std::exception &e)
2941         {
2942                 return false;
2943         }
2944         
2945         return true;
2946 }
2947
2948 #if 0
2949 bool ServerMap::loadSectorFull(v2s16 p2d)
2950 {
2951         DSTACK(__FUNCTION_NAME);
2952
2953         MapSector *sector = NULL;
2954
2955         // The directory layout we're going to load from.
2956         //  1 - original sectors/xxxxzzzz/
2957         //  2 - new sectors2/xxx/zzz/
2958         //  If we load from anything but the latest structure, we will
2959         //  immediately save to the new one, and remove the old.
2960         int loadlayout = 1;
2961         std::string sectordir1 = getSectorDir(p2d, 1);
2962         std::string sectordir;
2963         if(fs::PathExists(sectordir1))
2964         {
2965                 sectordir = sectordir1;
2966         }
2967         else
2968         {
2969                 loadlayout = 2;
2970                 sectordir = getSectorDir(p2d, 2);
2971         }
2972
2973         try{
2974                 sector = loadSectorMeta(sectordir, loadlayout != 2);
2975         }
2976         catch(InvalidFilenameException &e)
2977         {
2978                 return false;
2979         }
2980         catch(FileNotGoodException &e)
2981         {
2982                 return false;
2983         }
2984         catch(std::exception &e)
2985         {
2986                 return false;
2987         }
2988         
2989         /*
2990                 Load blocks
2991         */
2992         std::vector<fs::DirListNode> list2 = fs::GetDirListing
2993                         (sectordir);
2994         std::vector<fs::DirListNode>::iterator i2;
2995         for(i2=list2.begin(); i2!=list2.end(); i2++)
2996         {
2997                 // We want files
2998                 if(i2->dir)
2999                         continue;
3000                 try{
3001                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3002                 }
3003                 catch(InvalidFilenameException &e)
3004                 {
3005                         // This catches unknown crap in directory
3006                 }
3007         }
3008
3009         if(loadlayout != 2)
3010         {
3011                 dstream<<"Sector converted to new layout - deleting "<<
3012                         sectordir1<<std::endl;
3013                 fs::RecursiveDelete(sectordir1);
3014         }
3015
3016         return true;
3017 }
3018 #endif
3019
3020 void ServerMap::saveBlock(MapBlock *block)
3021 {
3022         DSTACK(__FUNCTION_NAME);
3023         /*
3024                 Dummy blocks are not written
3025         */
3026         if(block->isDummy())
3027         {
3028                 /*v3s16 p = block->getPos();
3029                 dstream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3030                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3031                 return;
3032         }
3033
3034         // Format used for writing
3035         u8 version = SER_FMT_VER_HIGHEST;
3036         // Get destination
3037         v3s16 p3d = block->getPos();
3038         
3039         v2s16 p2d(p3d.X, p3d.Z);
3040         std::string sectordir = getSectorDir(p2d);
3041
3042         createDirs(sectordir);
3043
3044         std::string fullpath = sectordir+"/"+getBlockFilename(p3d);
3045         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3046         if(o.good() == false)
3047                 throw FileNotGoodException("Cannot open block data");
3048
3049         /*
3050                 [0] u8 serialization version
3051                 [1] data
3052         */
3053         o.write((char*)&version, 1);
3054         
3055         // Write basic data
3056         block->serialize(o, version);
3057         
3058         // Write extra data stored on disk
3059         block->serializeDiskExtra(o, version);
3060
3061         // We just wrote it to the disk so clear modified flag
3062         block->resetModified();
3063 }
3064
3065 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3066 {
3067         DSTACK(__FUNCTION_NAME);
3068
3069         std::string fullpath = sectordir+"/"+blockfile;
3070         try{
3071
3072                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3073                 if(is.good() == false)
3074                         throw FileNotGoodException("Cannot open block file");
3075                 
3076                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3077                 v2s16 p2d(p3d.X, p3d.Z);
3078                 
3079                 assert(sector->getPos() == p2d);
3080                 
3081                 u8 version = SER_FMT_VER_INVALID;
3082                 is.read((char*)&version, 1);
3083
3084                 if(is.fail())
3085                         throw SerializationError("ServerMap::loadBlock(): Failed"
3086                                         " to read MapBlock version");
3087
3088                 /*u32 block_size = MapBlock::serializedLength(version);
3089                 SharedBuffer<u8> data(block_size);
3090                 is.read((char*)*data, block_size);*/
3091
3092                 // This will always return a sector because we're the server
3093                 //MapSector *sector = emergeSector(p2d);
3094
3095                 MapBlock *block = NULL;
3096                 bool created_new = false;
3097                 try{
3098                         block = sector->getBlockNoCreate(p3d.Y);
3099                 }
3100                 catch(InvalidPositionException &e)
3101                 {
3102                         block = sector->createBlankBlockNoInsert(p3d.Y);
3103                         created_new = true;
3104                 }
3105                 
3106                 // Read basic data
3107                 block->deSerialize(is, version);
3108
3109                 // Read extra data stored on disk
3110                 block->deSerializeDiskExtra(is, version);
3111                 
3112                 // If it's a new block, insert it to the map
3113                 if(created_new)
3114                         sector->insertBlock(block);
3115                 
3116                 /*
3117                         Save blocks loaded in old format in new format
3118                 */
3119
3120                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3121                 {
3122                         saveBlock(block);
3123                 }
3124                 
3125                 // We just loaded it from the disk, so it's up-to-date.
3126                 block->resetModified();
3127
3128         }
3129         catch(SerializationError &e)
3130         {
3131                 dstream<<"WARNING: Invalid block data on disk "
3132                                 <<"fullpath="<<fullpath
3133                                 <<" (SerializationError). "
3134                                 <<"what()="<<e.what()
3135                                 <<std::endl;
3136                                 //" Ignoring. A new one will be generated.
3137                 assert(0);
3138
3139                 // TODO: Backup file; name is in fullpath.
3140         }
3141 }
3142
3143 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3144 {
3145         DSTACK(__FUNCTION_NAME);
3146
3147         v2s16 p2d(blockpos.X, blockpos.Z);
3148
3149         // The directory layout we're going to load from.
3150         //  1 - original sectors/xxxxzzzz/
3151         //  2 - new sectors2/xxx/zzz/
3152         //  If we load from anything but the latest structure, we will
3153         //  immediately save to the new one, and remove the old.
3154         int loadlayout = 1;
3155         std::string sectordir1 = getSectorDir(p2d, 1);
3156         std::string sectordir;
3157         if(fs::PathExists(sectordir1))
3158         {
3159                 sectordir = sectordir1;
3160         }
3161         else
3162         {
3163                 loadlayout = 2;
3164                 sectordir = getSectorDir(p2d, 2);
3165         }
3166         
3167         /*
3168                 Make sure sector is loaded
3169         */
3170         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3171         if(sector == NULL)
3172         {
3173                 try{
3174                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3175                 }
3176                 catch(InvalidFilenameException &e)
3177                 {
3178                         return false;
3179                 }
3180                 catch(FileNotGoodException &e)
3181                 {
3182                         return false;
3183                 }
3184                 catch(std::exception &e)
3185                 {
3186                         return false;
3187                 }
3188         }
3189         
3190         /*
3191                 Make sure file exists
3192         */
3193
3194         std::string blockfilename = getBlockFilename(blockpos);
3195         if(fs::PathExists(sectordir+"/"+blockfilename) == false)
3196                 return NULL;
3197
3198         /*
3199                 Load block
3200         */
3201         loadBlock(sectordir, blockfilename, sector, loadlayout != 2);
3202         return getBlockNoCreateNoEx(blockpos);
3203 }
3204
3205 void ServerMap::PrintInfo(std::ostream &out)
3206 {
3207         out<<"ServerMap: ";
3208 }
3209
3210 #ifndef SERVER
3211
3212 /*
3213         ClientMap
3214 */
3215
3216 ClientMap::ClientMap(
3217                 Client *client,
3218                 MapDrawControl &control,
3219                 scene::ISceneNode* parent,
3220                 scene::ISceneManager* mgr,
3221                 s32 id
3222 ):
3223         Map(dout_client),
3224         scene::ISceneNode(parent, mgr, id),
3225         m_client(client),
3226         m_control(control),
3227         m_camera_position(0,0,0),
3228         m_camera_direction(0,0,1)
3229 {
3230         m_camera_mutex.Init();
3231         assert(m_camera_mutex.IsInitialized());
3232         
3233         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3234                         BS*1000000,BS*1000000,BS*1000000);
3235 }
3236
3237 ClientMap::~ClientMap()
3238 {
3239         /*JMutexAutoLock lock(mesh_mutex);
3240         
3241         if(mesh != NULL)
3242         {
3243                 mesh->drop();
3244                 mesh = NULL;
3245         }*/
3246 }
3247
3248 MapSector * ClientMap::emergeSector(v2s16 p2d)
3249 {
3250         DSTACK(__FUNCTION_NAME);
3251         // Check that it doesn't exist already
3252         try{
3253                 return getSectorNoGenerate(p2d);
3254         }
3255         catch(InvalidPositionException &e)
3256         {
3257         }
3258         
3259         // Create a sector
3260         ClientMapSector *sector = new ClientMapSector(this, p2d);
3261         
3262         {
3263                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3264                 m_sectors.insert(p2d, sector);
3265         }
3266         
3267         return sector;
3268 }
3269
3270 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3271 {
3272         DSTACK(__FUNCTION_NAME);
3273         ClientMapSector *sector = NULL;
3274
3275         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3276         
3277         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3278
3279         if(n != NULL)
3280         {
3281                 sector = (ClientMapSector*)n->getValue();
3282                 assert(sector->getId() == MAPSECTOR_CLIENT);
3283         }
3284         else
3285         {
3286                 sector = new ClientMapSector(this, p2d);
3287                 {
3288                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3289                         m_sectors.insert(p2d, sector);
3290                 }
3291         }
3292
3293         sector->deSerialize(is);
3294 }
3295
3296 void ClientMap::OnRegisterSceneNode()
3297 {
3298         if(IsVisible)
3299         {
3300                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3301                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3302         }
3303
3304         ISceneNode::OnRegisterSceneNode();
3305 }
3306
3307 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3308 {
3309         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3310         DSTACK(__FUNCTION_NAME);
3311
3312         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3313         
3314         /*
3315                 This is called two times per frame, reset on the non-transparent one
3316         */
3317         if(pass == scene::ESNRP_SOLID)
3318         {
3319                 m_last_drawn_sectors.clear();
3320         }
3321
3322         /*
3323                 Get time for measuring timeout.
3324                 
3325                 Measuring time is very useful for long delays when the
3326                 machine is swapping a lot.
3327         */
3328         int time1 = time(0);
3329
3330         //u32 daynight_ratio = m_client->getDayNightRatio();
3331
3332         m_camera_mutex.Lock();
3333         v3f camera_position = m_camera_position;
3334         v3f camera_direction = m_camera_direction;
3335         m_camera_mutex.Unlock();
3336
3337         /*
3338                 Get all blocks and draw all visible ones
3339         */
3340
3341         v3s16 cam_pos_nodes(
3342                         camera_position.X / BS,
3343                         camera_position.Y / BS,
3344                         camera_position.Z / BS);
3345
3346         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3347
3348         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3349         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3350
3351         // Take a fair amount as we will be dropping more out later
3352         v3s16 p_blocks_min(
3353                         p_nodes_min.X / MAP_BLOCKSIZE - 1,
3354                         p_nodes_min.Y / MAP_BLOCKSIZE - 1,
3355                         p_nodes_min.Z / MAP_BLOCKSIZE - 1);
3356         v3s16 p_blocks_max(
3357                         p_nodes_max.X / MAP_BLOCKSIZE,
3358                         p_nodes_max.Y / MAP_BLOCKSIZE,
3359                         p_nodes_max.Z / MAP_BLOCKSIZE);
3360         
3361         u32 vertex_count = 0;
3362         
3363         // For limiting number of mesh updates per frame
3364         u32 mesh_update_count = 0;
3365         
3366         u32 blocks_would_have_drawn = 0;
3367         u32 blocks_drawn = 0;
3368
3369         int timecheck_counter = 0;
3370         core::map<v2s16, MapSector*>::Iterator si;
3371         si = m_sectors.getIterator();
3372         for(; si.atEnd() == false; si++)
3373         {
3374                 {
3375                         timecheck_counter++;
3376                         if(timecheck_counter > 50)
3377                         {
3378                                 timecheck_counter = 0;
3379                                 int time2 = time(0);
3380                                 if(time2 > time1 + 4)
3381                                 {
3382                                         dstream<<"ClientMap::renderMap(): "
3383                                                 "Rendering takes ages, returning."
3384                                                 <<std::endl;
3385                                         return;
3386                                 }
3387                         }
3388                 }
3389
3390                 MapSector *sector = si.getNode()->getValue();
3391                 v2s16 sp = sector->getPos();
3392                 
3393                 if(m_control.range_all == false)
3394                 {
3395                         if(sp.X < p_blocks_min.X
3396                         || sp.X > p_blocks_max.X
3397                         || sp.Y < p_blocks_min.Z
3398                         || sp.Y > p_blocks_max.Z)
3399                                 continue;
3400                 }
3401
3402                 core::list< MapBlock * > sectorblocks;
3403                 sector->getBlocks(sectorblocks);
3404                 
3405                 /*
3406                         Draw blocks
3407                 */
3408                 
3409                 u32 sector_blocks_drawn = 0;
3410
3411                 core::list< MapBlock * >::Iterator i;
3412                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3413                 {
3414                         MapBlock *block = *i;
3415
3416                         /*
3417                                 Compare block position to camera position, skip
3418                                 if not seen on display
3419                         */
3420                         
3421                         float range = 100000 * BS;
3422                         if(m_control.range_all == false)
3423                                 range = m_control.wanted_range * BS;
3424                         
3425                         float d = 0.0;
3426                         if(isBlockInSight(block->getPos(), camera_position,
3427                                         camera_direction, range, &d) == false)
3428                         {
3429                                 continue;
3430                         }
3431                         
3432                         // This is ugly (spherical distance limit?)
3433                         /*if(m_control.range_all == false &&
3434                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3435                                 continue;*/
3436
3437 #if 1
3438                         /*
3439                                 Update expired mesh (used for day/night change)
3440
3441                                 It doesn't work exactly like it should now with the
3442                                 tasked mesh update but whatever.
3443                         */
3444
3445                         bool mesh_expired = false;
3446                         
3447                         {
3448                                 JMutexAutoLock lock(block->mesh_mutex);
3449
3450                                 mesh_expired = block->getMeshExpired();
3451
3452                                 // Mesh has not been expired and there is no mesh:
3453                                 // block has no content
3454                                 if(block->mesh == NULL && mesh_expired == false)
3455                                         continue;
3456                         }
3457
3458                         f32 faraway = BS*50;
3459                         //f32 faraway = m_control.wanted_range * BS;
3460                         
3461                         /*
3462                                 This has to be done with the mesh_mutex unlocked
3463                         */
3464                         // Pretty random but this should work somewhat nicely
3465                         if(mesh_expired && (
3466                                         (mesh_update_count < 3
3467                                                 && (d < faraway || mesh_update_count < 2)
3468                                         )
3469                                         || 
3470                                         (m_control.range_all && mesh_update_count < 20)
3471                                 )
3472                         )
3473                         /*if(mesh_expired && mesh_update_count < 6
3474                                         && (d < faraway || mesh_update_count < 3))*/
3475                         {
3476                                 mesh_update_count++;
3477
3478                                 // Mesh has been expired: generate new mesh
3479                                 //block->updateMesh(daynight_ratio);
3480                                 m_client->addUpdateMeshTask(block->getPos());
3481
3482                                 mesh_expired = false;
3483                         }
3484                         
3485 #endif
3486                         /*
3487                                 Draw the faces of the block
3488                         */
3489                         {
3490                                 JMutexAutoLock lock(block->mesh_mutex);
3491
3492                                 scene::SMesh *mesh = block->mesh;
3493
3494                                 if(mesh == NULL)
3495                                         continue;
3496                                 
3497                                 blocks_would_have_drawn++;
3498                                 if(blocks_drawn >= m_control.wanted_max_blocks
3499                                                 && m_control.range_all == false
3500                                                 && d > m_control.wanted_min_range * BS)
3501                                         continue;
3502
3503                                 blocks_drawn++;
3504                                 sector_blocks_drawn++;
3505
3506                                 u32 c = mesh->getMeshBufferCount();
3507
3508                                 for(u32 i=0; i<c; i++)
3509                                 {
3510                                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3511                                         const video::SMaterial& material = buf->getMaterial();
3512                                         video::IMaterialRenderer* rnd =
3513                                                         driver->getMaterialRenderer(material.MaterialType);
3514                                         bool transparent = (rnd && rnd->isTransparent());
3515                                         // Render transparent on transparent pass and likewise.
3516                                         if(transparent == is_transparent_pass)
3517                                         {
3518                                                 /*
3519                                                         This *shouldn't* hurt too much because Irrlicht
3520                                                         doesn't change opengl textures if the old
3521                                                         material is set again.
3522                                                 */
3523                                                 driver->setMaterial(buf->getMaterial());
3524                                                 driver->drawMeshBuffer(buf);
3525                                                 vertex_count += buf->getVertexCount();
3526                                         }
3527                                 }
3528                         }
3529                 } // foreach sectorblocks
3530
3531                 if(sector_blocks_drawn != 0)
3532                 {
3533                         m_last_drawn_sectors[sp] = true;
3534                 }
3535         }
3536         
3537         m_control.blocks_drawn = blocks_drawn;
3538         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
3539
3540         /*dstream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
3541                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
3542 }
3543
3544 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
3545                 core::map<v3s16, MapBlock*> *affected_blocks)
3546 {
3547         bool changed = false;
3548         /*
3549                 Add it to all blocks touching it
3550         */
3551         v3s16 dirs[7] = {
3552                 v3s16(0,0,0), // this
3553                 v3s16(0,0,1), // back
3554                 v3s16(0,1,0), // top
3555                 v3s16(1,0,0), // right
3556                 v3s16(0,0,-1), // front
3557                 v3s16(0,-1,0), // bottom
3558                 v3s16(-1,0,0), // left
3559         };
3560         for(u16 i=0; i<7; i++)
3561         {
3562                 v3s16 p2 = p + dirs[i];
3563                 // Block position of neighbor (or requested) node
3564                 v3s16 blockpos = getNodeBlockPos(p2);
3565                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3566                 if(blockref == NULL)
3567                         continue;
3568                 // Relative position of requested node
3569                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3570                 if(blockref->setTempMod(relpos, mod))
3571                 {
3572                         changed = true;
3573                 }
3574         }
3575         if(changed && affected_blocks!=NULL)
3576         {
3577                 for(u16 i=0; i<7; i++)
3578                 {
3579                         v3s16 p2 = p + dirs[i];
3580                         // Block position of neighbor (or requested) node
3581                         v3s16 blockpos = getNodeBlockPos(p2);
3582                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3583                         if(blockref == NULL)
3584                                 continue;
3585                         affected_blocks->insert(blockpos, blockref);
3586                 }
3587         }
3588         return changed;
3589 }
3590
3591 bool ClientMap::clearTempMod(v3s16 p,
3592                 core::map<v3s16, MapBlock*> *affected_blocks)
3593 {
3594         bool changed = false;
3595         v3s16 dirs[7] = {
3596                 v3s16(0,0,0), // this
3597                 v3s16(0,0,1), // back
3598                 v3s16(0,1,0), // top
3599                 v3s16(1,0,0), // right
3600                 v3s16(0,0,-1), // front
3601                 v3s16(0,-1,0), // bottom
3602                 v3s16(-1,0,0), // left
3603         };
3604         for(u16 i=0; i<7; i++)
3605         {
3606                 v3s16 p2 = p + dirs[i];
3607                 // Block position of neighbor (or requested) node
3608                 v3s16 blockpos = getNodeBlockPos(p2);
3609                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3610                 if(blockref == NULL)
3611                         continue;
3612                 // Relative position of requested node
3613                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
3614                 if(blockref->clearTempMod(relpos))
3615                 {
3616                         changed = true;
3617                 }
3618         }
3619         if(changed && affected_blocks!=NULL)
3620         {
3621                 for(u16 i=0; i<7; i++)
3622                 {
3623                         v3s16 p2 = p + dirs[i];
3624                         // Block position of neighbor (or requested) node
3625                         v3s16 blockpos = getNodeBlockPos(p2);
3626                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
3627                         if(blockref == NULL)
3628                                 continue;
3629                         affected_blocks->insert(blockpos, blockref);
3630                 }
3631         }
3632         return changed;
3633 }
3634
3635 void ClientMap::expireMeshes(bool only_daynight_diffed)
3636 {
3637         TimeTaker timer("expireMeshes()");
3638
3639         core::map<v2s16, MapSector*>::Iterator si;
3640         si = m_sectors.getIterator();
3641         for(; si.atEnd() == false; si++)
3642         {
3643                 MapSector *sector = si.getNode()->getValue();
3644
3645                 core::list< MapBlock * > sectorblocks;
3646                 sector->getBlocks(sectorblocks);
3647                 
3648                 core::list< MapBlock * >::Iterator i;
3649                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3650                 {
3651                         MapBlock *block = *i;
3652
3653                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
3654                         {
3655                                 continue;
3656                         }
3657                         
3658                         {
3659                                 JMutexAutoLock lock(block->mesh_mutex);
3660                                 if(block->mesh != NULL)
3661                                 {
3662                                         /*block->mesh->drop();
3663                                         block->mesh = NULL;*/
3664                                         block->setMeshExpired(true);
3665                                 }
3666                         }
3667                 }
3668         }
3669 }
3670
3671 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
3672 {
3673         assert(mapType() == MAPTYPE_CLIENT);
3674
3675         try{
3676                 v3s16 p = blockpos + v3s16(0,0,0);
3677                 MapBlock *b = getBlockNoCreate(p);
3678                 b->updateMesh(daynight_ratio);
3679                 //b->setMeshExpired(true);
3680         }
3681         catch(InvalidPositionException &e){}
3682         // Leading edge
3683         try{
3684                 v3s16 p = blockpos + v3s16(-1,0,0);
3685                 MapBlock *b = getBlockNoCreate(p);
3686                 b->updateMesh(daynight_ratio);
3687                 //b->setMeshExpired(true);
3688         }
3689         catch(InvalidPositionException &e){}
3690         try{
3691                 v3s16 p = blockpos + v3s16(0,-1,0);
3692                 MapBlock *b = getBlockNoCreate(p);
3693                 b->updateMesh(daynight_ratio);
3694                 //b->setMeshExpired(true);
3695         }
3696         catch(InvalidPositionException &e){}
3697         try{
3698                 v3s16 p = blockpos + v3s16(0,0,-1);
3699                 MapBlock *b = getBlockNoCreate(p);
3700                 b->updateMesh(daynight_ratio);
3701                 //b->setMeshExpired(true);
3702         }
3703         catch(InvalidPositionException &e){}
3704 }
3705
3706 #if 0
3707 /*
3708         Update mesh of block in which the node is, and if the node is at the
3709         leading edge, update the appropriate leading blocks too.
3710 */
3711 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
3712 {
3713         v3s16 dirs[4] = {
3714                 v3s16(0,0,0),
3715                 v3s16(-1,0,0),
3716                 v3s16(0,-1,0),
3717                 v3s16(0,0,-1),
3718         };
3719         v3s16 blockposes[4];
3720         for(u32 i=0; i<4; i++)
3721         {
3722                 v3s16 np = nodepos + dirs[i];
3723                 blockposes[i] = getNodeBlockPos(np);
3724                 // Don't update mesh of block if it has been done already
3725                 bool already_updated = false;
3726                 for(u32 j=0; j<i; j++)
3727                 {
3728                         if(blockposes[j] == blockposes[i])
3729                         {
3730                                 already_updated = true;
3731                                 break;
3732                         }
3733                 }
3734                 if(already_updated)
3735                         continue;
3736                 // Update mesh
3737                 MapBlock *b = getBlockNoCreate(blockposes[i]);
3738                 b->updateMesh(daynight_ratio);
3739         }
3740 }
3741 #endif
3742
3743 void ClientMap::PrintInfo(std::ostream &out)
3744 {
3745         out<<"ClientMap: ";
3746 }
3747
3748 #endif // !SERVER
3749
3750 /*
3751         MapVoxelManipulator
3752 */
3753
3754 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3755 {
3756         m_map = map;
3757 }
3758
3759 MapVoxelManipulator::~MapVoxelManipulator()
3760 {
3761         /*dstream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3762                         <<std::endl;*/
3763 }
3764
3765 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3766 {
3767         TimeTaker timer1("emerge", &emerge_time);
3768
3769         // Units of these are MapBlocks
3770         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3771         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3772
3773         VoxelArea block_area_nodes
3774                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3775
3776         addArea(block_area_nodes);
3777
3778         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3779         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3780         for(s32 x=p_min.X; x<=p_max.X; x++)
3781         {
3782                 v3s16 p(x,y,z);
3783                 core::map<v3s16, bool>::Node *n;
3784                 n = m_loaded_blocks.find(p);
3785                 if(n != NULL)
3786                         continue;
3787                 
3788                 bool block_data_inexistent = false;
3789                 try
3790                 {
3791                         TimeTaker timer1("emerge load", &emerge_load_time);
3792
3793                         /*dstream<<"Loading block (caller_id="<<caller_id<<")"
3794                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3795                                         <<" wanted area: ";
3796                         a.print(dstream);
3797                         dstream<<std::endl;*/
3798                         
3799                         MapBlock *block = m_map->getBlockNoCreate(p);
3800                         if(block->isDummy())
3801                                 block_data_inexistent = true;
3802                         else
3803                                 block->copyTo(*this);
3804                 }
3805                 catch(InvalidPositionException &e)
3806                 {
3807                         block_data_inexistent = true;
3808                 }
3809
3810                 if(block_data_inexistent)
3811                 {
3812                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3813                         // Fill with VOXELFLAG_INEXISTENT
3814                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3815                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3816                         {
3817                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3818                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3819                         }
3820                 }
3821
3822                 m_loaded_blocks.insert(p, !block_data_inexistent);
3823         }
3824
3825         //dstream<<"emerge done"<<std::endl;
3826 }
3827
3828 /*
3829         SUGG: Add an option to only update eg. water and air nodes.
3830               This will make it interfere less with important stuff if
3831                   run on background.
3832 */
3833 void MapVoxelManipulator::blitBack
3834                 (core::map<v3s16, MapBlock*> & modified_blocks)
3835 {
3836         if(m_area.getExtent() == v3s16(0,0,0))
3837                 return;
3838         
3839         //TimeTaker timer1("blitBack");
3840
3841         /*dstream<<"blitBack(): m_loaded_blocks.size()="
3842                         <<m_loaded_blocks.size()<<std::endl;*/
3843         
3844         /*
3845                 Initialize block cache
3846         */
3847         v3s16 blockpos_last;
3848         MapBlock *block = NULL;
3849         bool block_checked_in_modified = false;
3850
3851         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3852         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3853         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3854         {
3855                 v3s16 p(x,y,z);
3856
3857                 u8 f = m_flags[m_area.index(p)];
3858                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3859                         continue;
3860
3861                 MapNode &n = m_data[m_area.index(p)];
3862                         
3863                 v3s16 blockpos = getNodeBlockPos(p);
3864                 
3865                 try
3866                 {
3867                         // Get block
3868                         if(block == NULL || blockpos != blockpos_last){
3869                                 block = m_map->getBlockNoCreate(blockpos);
3870                                 blockpos_last = blockpos;
3871                                 block_checked_in_modified = false;
3872                         }
3873                         
3874                         // Calculate relative position in block
3875                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3876
3877                         // Don't continue if nothing has changed here
3878                         if(block->getNode(relpos) == n)
3879                                 continue;
3880
3881                         //m_map->setNode(m_area.MinEdge + p, n);
3882                         block->setNode(relpos, n);
3883                         
3884                         /*
3885                                 Make sure block is in modified_blocks
3886                         */
3887                         if(block_checked_in_modified == false)
3888                         {
3889                                 modified_blocks[blockpos] = block;
3890                                 block_checked_in_modified = true;
3891                         }
3892                 }
3893                 catch(InvalidPositionException &e)
3894                 {
3895                 }
3896         }
3897 }
3898
3899 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
3900                 MapVoxelManipulator(map),
3901                 m_create_area(false)
3902 {
3903 }
3904
3905 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
3906 {
3907 }
3908
3909 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3910 {
3911         // Just create the area so that it can be pointed to
3912         VoxelManipulator::emerge(a, caller_id);
3913 }
3914
3915 void ManualMapVoxelManipulator::initialEmerge(
3916                 v3s16 blockpos_min, v3s16 blockpos_max)
3917 {
3918         TimeTaker timer1("initialEmerge", &emerge_time);
3919
3920         // Units of these are MapBlocks
3921         v3s16 p_min = blockpos_min;
3922         v3s16 p_max = blockpos_max;
3923
3924         VoxelArea block_area_nodes
3925                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3926         
3927         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3928         if(size_MB >= 1)
3929         {
3930                 dstream<<"initialEmerge: area: ";
3931                 block_area_nodes.print(dstream);
3932                 dstream<<" ("<<size_MB<<"MB)";
3933                 dstream<<std::endl;
3934         }
3935
3936         addArea(block_area_nodes);
3937
3938         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3939         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3940         for(s32 x=p_min.X; x<=p_max.X; x++)
3941         {
3942                 v3s16 p(x,y,z);
3943                 core::map<v3s16, bool>::Node *n;
3944                 n = m_loaded_blocks.find(p);
3945                 if(n != NULL)
3946                         continue;
3947                 
3948                 bool block_data_inexistent = false;
3949                 try
3950                 {
3951                         TimeTaker timer1("emerge load", &emerge_load_time);
3952
3953                         MapBlock *block = m_map->getBlockNoCreate(p);
3954                         if(block->isDummy())
3955                                 block_data_inexistent = true;
3956                         else
3957                                 block->copyTo(*this);
3958                 }
3959                 catch(InvalidPositionException &e)
3960                 {
3961                         block_data_inexistent = true;
3962                 }
3963
3964                 if(block_data_inexistent)
3965                 {
3966                         /*
3967                                 Mark area inexistent
3968                         */
3969                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3970                         // Fill with VOXELFLAG_INEXISTENT
3971                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3972                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3973                         {
3974                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3975                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3976                         }
3977                 }
3978
3979                 m_loaded_blocks.insert(p, !block_data_inexistent);
3980         }
3981 }
3982
3983 void ManualMapVoxelManipulator::blitBackAll(
3984                 core::map<v3s16, MapBlock*> * modified_blocks)
3985 {
3986         if(m_area.getExtent() == v3s16(0,0,0))
3987                 return;
3988         
3989         /*
3990                 Copy data of all blocks
3991         */
3992         for(core::map<v3s16, bool>::Iterator
3993                         i = m_loaded_blocks.getIterator();
3994                         i.atEnd() == false; i++)
3995         {
3996                 bool existed = i.getNode()->getValue();
3997                 if(existed == false)
3998                         continue;
3999                 v3s16 p = i.getNode()->getKey();
4000                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4001                 if(block == NULL)
4002                 {
4003                         dstream<<"WARNING: "<<__FUNCTION_NAME
4004                                         <<": got NULL block "
4005                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4006                                         <<std::endl;
4007                         continue;
4008                 }
4009
4010                 block->copyFrom(*this);
4011
4012                 if(modified_blocks)
4013                         modified_blocks->insert(p, block);
4014         }
4015 }
4016
4017 //END