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