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