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