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