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