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