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