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