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