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