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