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