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