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