]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
GenericNodeMetadata and an example furnace
[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(errorstream);
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                                                 sources[num_sources++] = nb;
1687                                         }
1688                                         break;
1689                                 case LIQUID_FLOWING:
1690                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1691                                         if (liquid_kind == CONTENT_AIR)
1692                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1693                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1694                                                 neutrals[num_neutrals++] = nb;
1695                                         } else {
1696                                                 flows[num_flows++] = nb;
1697                                                 if (nb.t == NEIGHBOR_LOWER)
1698                                                         flowing_down = true;
1699                                         }
1700                                         break;
1701                         }
1702                 }
1703
1704                 /*
1705                         decide on the type (and possibly level) of the current node
1706                  */
1707                 content_t new_node_content;
1708                 s8 new_node_level = -1;
1709                 s8 max_node_level = -1;
1710                 if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) {
1711                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1712                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1713                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1714                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1715                 } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) {
1716                         // liquid_kind is set properly, see above
1717                         new_node_content = liquid_kind;
1718                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1719                 } else {
1720                         // no surrounding sources, so get the maximum level that can flow into this node
1721                         for (u16 i = 0; i < num_flows; i++) {
1722                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1723                                 switch (flows[i].t) {
1724                                         case NEIGHBOR_UPPER:
1725                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1726                                                         max_node_level = LIQUID_LEVEL_MAX;
1727                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1728                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1729                                                 } else if (nb_liquid_level > max_node_level)
1730                                                         max_node_level = nb_liquid_level;
1731                                                 break;
1732                                         case NEIGHBOR_LOWER:
1733                                                 break;
1734                                         case NEIGHBOR_SAME_LEVEL:
1735                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1736                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1737                                                         max_node_level = nb_liquid_level - 1;
1738                                                 }
1739                                                 break;
1740                                 }
1741                         }
1742
1743                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1744                         if (viscosity > 1 && max_node_level != liquid_level) {
1745                                 // amount to gain, limited by viscosity
1746                                 // must be at least 1 in absolute value
1747                                 s8 level_inc = max_node_level - liquid_level;
1748                                 if (level_inc < -viscosity || level_inc > viscosity)
1749                                         new_node_level = liquid_level + level_inc/viscosity;
1750                                 else if (level_inc < 0)
1751                                         new_node_level = liquid_level - 1;
1752                                 else if (level_inc > 0)
1753                                         new_node_level = liquid_level + 1;
1754                                 if (new_node_level != max_node_level)
1755                                         must_reflow.push_back(p0);
1756                         } else
1757                                 new_node_level = max_node_level;
1758
1759                         if (new_node_level >= 0)
1760                                 new_node_content = liquid_kind;
1761                         else
1762                                 new_node_content = CONTENT_AIR;
1763
1764                 }
1765
1766                 /*
1767                         check if anything has changed. if not, just continue with the next node.
1768                  */
1769                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1770                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1771                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1772                                                                                  == flowing_down)))
1773                         continue;
1774
1775
1776                 /*
1777                         update the current node
1778                  */
1779                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1780                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1781                         // set level to last 3 bits, flowing down bit to 4th bit
1782                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1783                 } else {
1784                         // set the liquid level and flow bit to 0
1785                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1786                 }
1787                 n0.setContent(new_node_content);
1788                 setNode(p0, n0);
1789                 v3s16 blockpos = getNodeBlockPos(p0);
1790                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1791                 if(block != NULL) {
1792                         modified_blocks.insert(blockpos, block);
1793                         // If node emits light, MapBlock requires lighting update
1794                         if(nodemgr->get(n0).light_source != 0)
1795                                 lighting_modified_blocks[block->getPos()] = block;
1796                 }
1797
1798                 /*
1799                         enqueue neighbors for update if neccessary
1800                  */
1801                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1802                         case LIQUID_SOURCE:
1803                         case LIQUID_FLOWING:
1804                                 // make sure source flows into all neighboring nodes
1805                                 for (u16 i = 0; i < num_flows; i++)
1806                                         if (flows[i].t != NEIGHBOR_UPPER)
1807                                                 m_transforming_liquid.push_back(flows[i].p);
1808                                 for (u16 i = 0; i < num_airs; i++)
1809                                         if (airs[i].t != NEIGHBOR_UPPER)
1810                                                 m_transforming_liquid.push_back(airs[i].p);
1811                                 break;
1812                         case LIQUID_NONE:
1813                                 // this flow has turned to air; neighboring flows might need to do the same
1814                                 for (u16 i = 0; i < num_flows; i++)
1815                                         m_transforming_liquid.push_back(flows[i].p);
1816                                 break;
1817                 }
1818         }
1819         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1820         while (must_reflow.size() > 0)
1821                 m_transforming_liquid.push_back(must_reflow.pop_front());
1822         updateLighting(lighting_modified_blocks, modified_blocks);
1823 }
1824
1825 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1826 {
1827         v3s16 blockpos = getNodeBlockPos(p);
1828         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1829         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1830         if(!block){
1831                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1832                                 <<PP(blockpos)<<std::endl;
1833                 block = emergeBlock(blockpos, false);
1834         }
1835         if(!block)
1836         {
1837                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
1838                                 <<std::endl;
1839                 return NULL;
1840         }
1841         NodeMetadata *meta = block->m_node_metadata->get(p_rel);
1842         return meta;
1843 }
1844
1845 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1846 {
1847         v3s16 blockpos = getNodeBlockPos(p);
1848         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1849         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1850         if(!block){
1851                 infostream<<"Map::setNodeMetadata(): Need to emerge "
1852                                 <<PP(blockpos)<<std::endl;
1853                 block = emergeBlock(blockpos, false);
1854         }
1855         if(!block)
1856         {
1857                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
1858                                 <<std::endl;
1859                 return;
1860         }
1861         block->m_node_metadata->set(p_rel, meta);
1862 }
1863
1864 void Map::removeNodeMetadata(v3s16 p)
1865 {
1866         v3s16 blockpos = getNodeBlockPos(p);
1867         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1868         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1869         if(block == NULL)
1870         {
1871                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1872                                 <<std::endl;
1873                 return;
1874         }
1875         block->m_node_metadata->remove(p_rel);
1876 }
1877
1878 void Map::nodeMetadataStep(float dtime,
1879                 core::map<v3s16, MapBlock*> &changed_blocks)
1880 {
1881         /*
1882                 NOTE:
1883                 Currently there is no way to ensure that all the necessary
1884                 blocks are loaded when this is run. (They might get unloaded)
1885                 NOTE: ^- Actually, that might not be so. In a quick test it
1886                 reloaded a block with a furnace when I walked back to it from
1887                 a distance.
1888         */
1889         core::map<v2s16, MapSector*>::Iterator si;
1890         si = m_sectors.getIterator();
1891         for(; si.atEnd() == false; si++)
1892         {
1893                 MapSector *sector = si.getNode()->getValue();
1894                 core::list< MapBlock * > sectorblocks;
1895                 sector->getBlocks(sectorblocks);
1896                 core::list< MapBlock * >::Iterator i;
1897                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
1898                 {
1899                         MapBlock *block = *i;
1900                         bool changed = block->m_node_metadata->step(dtime);
1901                         if(changed)
1902                                 changed_blocks[block->getPos()] = block;
1903                 }
1904         }
1905 }
1906
1907 /*
1908         ServerMap
1909 */
1910
1911 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef):
1912         Map(dout_server, gamedef),
1913         m_seed(0),
1914         m_map_metadata_changed(true),
1915         m_database(NULL),
1916         m_database_read(NULL),
1917         m_database_write(NULL)
1918 {
1919         infostream<<__FUNCTION_NAME<<std::endl;
1920
1921         //m_chunksize = 8; // Takes a few seconds
1922
1923         if (g_settings->get("fixed_map_seed").empty())
1924         {
1925                 m_seed = (((u64)(myrand()%0xffff)<<0)
1926                                 + ((u64)(myrand()%0xffff)<<16)
1927                                 + ((u64)(myrand()%0xffff)<<32)
1928                                 + ((u64)(myrand()%0xffff)<<48));
1929         }
1930         else
1931         {
1932                 m_seed = g_settings->getU64("fixed_map_seed");
1933         }
1934
1935         /*
1936                 Experimental and debug stuff
1937         */
1938
1939         {
1940         }
1941
1942         /*
1943                 Try to load map; if not found, create a new one.
1944         */
1945
1946         m_savedir = savedir;
1947         m_map_saving_enabled = false;
1948
1949         try
1950         {
1951                 // If directory exists, check contents and load if possible
1952                 if(fs::PathExists(m_savedir))
1953                 {
1954                         // If directory is empty, it is safe to save into it.
1955                         if(fs::GetDirListing(m_savedir).size() == 0)
1956                         {
1957                                 infostream<<"Server: Empty save directory is valid."
1958                                                 <<std::endl;
1959                                 m_map_saving_enabled = true;
1960                         }
1961                         else
1962                         {
1963                                 try{
1964                                         // Load map metadata (seed, chunksize)
1965                                         loadMapMeta();
1966                                 }
1967                                 catch(FileNotGoodException &e){
1968                                         infostream<<"WARNING: Could not load map metadata"
1969                                                         //<<" Disabling chunk-based generator."
1970                                                         <<std::endl;
1971                                         //m_chunksize = 0;
1972                                 }
1973
1974                                 /*try{
1975                                         // Load chunk metadata
1976                                         loadChunkMeta();
1977                                 }
1978                                 catch(FileNotGoodException &e){
1979                                         infostream<<"WARNING: Could not load chunk metadata."
1980                                                         <<" Disabling chunk-based generator."
1981                                                         <<std::endl;
1982                                         m_chunksize = 0;
1983                                 }*/
1984
1985                                 /*infostream<<"Server: Successfully loaded chunk "
1986                                                 "metadata and sector (0,0) from "<<savedir<<
1987                                                 ", assuming valid save directory."
1988                                                 <<std::endl;*/
1989
1990                                 infostream<<"Server: Successfully loaded map "
1991                                                 <<"and chunk metadata from "<<savedir
1992                                                 <<", assuming valid save directory."
1993                                                 <<std::endl;
1994
1995                                 m_map_saving_enabled = true;
1996                                 // Map loaded, not creating new one
1997                                 return;
1998                         }
1999                 }
2000                 // If directory doesn't exist, it is safe to save to it
2001                 else{
2002                         m_map_saving_enabled = true;
2003                 }
2004         }
2005         catch(std::exception &e)
2006         {
2007                 infostream<<"WARNING: Server: Failed to load map from "<<savedir
2008                                 <<", exception: "<<e.what()<<std::endl;
2009                 infostream<<"Please remove the map or fix it."<<std::endl;
2010                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2011         }
2012
2013         infostream<<"Initializing new map."<<std::endl;
2014
2015         // Create zero sector
2016         emergeSector(v2s16(0,0));
2017
2018         // Initially write whole map
2019         save(MOD_STATE_CLEAN);
2020 }
2021
2022 ServerMap::~ServerMap()
2023 {
2024         infostream<<__FUNCTION_NAME<<std::endl;
2025
2026         try
2027         {
2028                 if(m_map_saving_enabled)
2029                 {
2030                         // Save only changed parts
2031                         save(MOD_STATE_WRITE_AT_UNLOAD);
2032                         infostream<<"Server: saved map to "<<m_savedir<<std::endl;
2033                 }
2034                 else
2035                 {
2036                         infostream<<"Server: map not saved"<<std::endl;
2037                 }
2038         }
2039         catch(std::exception &e)
2040         {
2041                 infostream<<"Server: Failed to save map to "<<m_savedir
2042                                 <<", exception: "<<e.what()<<std::endl;
2043         }
2044
2045         /*
2046                 Close database if it was opened
2047         */
2048         if(m_database_read)
2049                 sqlite3_finalize(m_database_read);
2050         if(m_database_write)
2051                 sqlite3_finalize(m_database_write);
2052         if(m_database)
2053                 sqlite3_close(m_database);
2054
2055 #if 0
2056         /*
2057                 Free all MapChunks
2058         */
2059         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2060         for(; i.atEnd() == false; i++)
2061         {
2062                 MapChunk *chunk = i.getNode()->getValue();
2063                 delete chunk;
2064         }
2065 #endif
2066 }
2067
2068 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
2069 {
2070         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2071         if(enable_mapgen_debug_info)
2072                 infostream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2073                                 <<blockpos.Z<<")"<<std::endl;
2074         
2075         // Do nothing if not inside limits (+-1 because of neighbors)
2076         if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
2077                 blockpos_over_limit(blockpos + v3s16(1,1,1)))
2078         {
2079                 data->no_op = true;
2080                 return;
2081         }
2082         
2083         data->no_op = false;
2084         data->seed = m_seed;
2085         data->blockpos = blockpos;
2086         data->nodedef = m_gamedef->ndef();
2087
2088         /*
2089                 Create the whole area of this and the neighboring blocks
2090         */
2091         {
2092                 //TimeTaker timer("initBlockMake() create area");
2093                 
2094                 for(s16 x=-1; x<=1; x++)
2095                 for(s16 z=-1; z<=1; z++)
2096                 {
2097                         v2s16 sectorpos(blockpos.X+x, blockpos.Z+z);
2098                         // Sector metadata is loaded from disk if not already loaded.
2099                         ServerMapSector *sector = createSector(sectorpos);
2100                         assert(sector);
2101
2102                         for(s16 y=-1; y<=1; y++)
2103                         {
2104                                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2105                                 //MapBlock *block = createBlock(p);
2106                                 // 1) get from memory, 2) load from disk
2107                                 MapBlock *block = emergeBlock(p, false);
2108                                 // 3) create a blank one
2109                                 if(block == NULL)
2110                                 {
2111                                         block = createBlock(p);
2112
2113                                         /*
2114                                                 Block gets sunlight if this is true.
2115
2116                                                 Refer to the map generator heuristics.
2117                                         */
2118                                         bool ug = mapgen::block_is_underground(data->seed, p);
2119                                         block->setIsUnderground(ug);
2120                                 }
2121
2122                                 // Lighting will not be valid after make_chunk is called
2123                                 block->setLightingExpired(true);
2124                                 // Lighting will be calculated
2125                                 //block->setLightingExpired(false);
2126                         }
2127                 }
2128         }
2129         
2130         /*
2131                 Now we have a big empty area.
2132
2133                 Make a ManualMapVoxelManipulator that contains this and the
2134                 neighboring blocks
2135         */
2136         
2137         // The area that contains this block and it's neighbors
2138         v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
2139         v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
2140         
2141         data->vmanip = new ManualMapVoxelManipulator(this);
2142         //data->vmanip->setMap(this);
2143
2144         // Add the area
2145         {
2146                 //TimeTaker timer("initBlockMake() initialEmerge");
2147                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2148         }
2149
2150         // Data is ready now.
2151 }
2152
2153 MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
2154                 core::map<v3s16, MapBlock*> &changed_blocks)
2155 {
2156         v3s16 blockpos = data->blockpos;
2157         /*infostream<<"finishBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
2158                         <<blockpos.Z<<")"<<std::endl;*/
2159
2160         if(data->no_op)
2161         {
2162                 //infostream<<"finishBlockMake(): no-op"<<std::endl;
2163                 return NULL;
2164         }
2165
2166         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2167
2168         /*infostream<<"Resulting vmanip:"<<std::endl;
2169         data->vmanip.print(infostream);*/
2170
2171         // Make sure affected blocks are loaded
2172         for(s16 x=-1; x<=1; x++)
2173         for(s16 z=-1; z<=1; z++)
2174         for(s16 y=-1; y<=1; y++)
2175         {
2176                 v3s16 p(blockpos.X+x, blockpos.Y+y, blockpos.Z+z);
2177                 // Load from disk if not already in memory
2178                 emergeBlock(p, false);
2179         }
2180
2181         /*
2182                 Blit generated stuff to map
2183                 NOTE: blitBackAll adds nearly everything to changed_blocks
2184         */
2185         {
2186                 // 70ms @cs=8
2187                 //TimeTaker timer("finishBlockMake() blitBackAll");
2188                 data->vmanip->blitBackAll(&changed_blocks);
2189         }
2190
2191         if(enable_mapgen_debug_info)
2192                 infostream<<"finishBlockMake: changed_blocks.size()="
2193                                 <<changed_blocks.size()<<std::endl;
2194
2195         /*
2196                 Copy transforming liquid information
2197         */
2198         while(data->transforming_liquid.size() > 0)
2199         {
2200                 v3s16 p = data->transforming_liquid.pop_front();
2201                 m_transforming_liquid.push_back(p);
2202         }
2203         
2204         /*
2205                 Get central block
2206         */
2207         MapBlock *block = getBlockNoCreateNoEx(data->blockpos);
2208         assert(block);
2209
2210         /*
2211                 Set is_underground flag for lighting with sunlight.
2212
2213                 Refer to map generator heuristics.
2214
2215                 NOTE: This is done in initChunkMake
2216         */
2217         //block->setIsUnderground(mapgen::block_is_underground(data->seed, blockpos));
2218
2219
2220         /*
2221                 Add sunlight to central block.
2222                 This makes in-dark-spawning monsters to not flood the whole thing.
2223                 Do not spread the light, though.
2224         */
2225         /*core::map<v3s16, bool> light_sources;
2226         bool black_air_left = false;
2227         block->propagateSunlight(light_sources, true, &black_air_left);*/
2228
2229         /*
2230                 NOTE: Lighting and object adding shouldn't really be here, but
2231                 lighting is a bit tricky to move properly to makeBlock.
2232                 TODO: Do this the right way anyway, that is, move it to makeBlock.
2233                       - There needs to be some way for makeBlock to report back if
2234                             the lighting update is going further down because of the
2235                                 new block blocking light
2236         */
2237
2238         /*
2239                 Update lighting
2240                 NOTE: This takes ~60ms, TODO: Investigate why
2241         */
2242         {
2243                 TimeTaker t("finishBlockMake lighting update");
2244
2245                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2246 #if 1
2247                 // Center block
2248                 lighting_update_blocks.insert(block->getPos(), block);
2249
2250                 /*{
2251                         s16 x = 0;
2252                         s16 z = 0;
2253                         v3s16 p = block->getPos()+v3s16(x,1,z);
2254                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2255                 }*/
2256 #endif
2257 #if 0
2258                 // All modified blocks
2259                 // NOTE: Should this be done? If this is not done, then the lighting
2260                 // of the others will be updated in a different place, one by one, i
2261                 // think... or they might not? Well, at least they are left marked as
2262                 // "lighting expired"; it seems that is not handled at all anywhere,
2263                 // so enabling this will slow it down A LOT because otherwise it
2264                 // would not do this at all. This causes the black trees.
2265                 for(core::map<v3s16, MapBlock*>::Iterator
2266                                 i = changed_blocks.getIterator();
2267                                 i.atEnd() == false; i++)
2268                 {
2269                         lighting_update_blocks.insert(i.getNode()->getKey(),
2270                                         i.getNode()->getValue());
2271                 }
2272                 /*// Also force-add all the upmost blocks for proper sunlight
2273                 for(s16 x=-1; x<=1; x++)
2274                 for(s16 z=-1; z<=1; z++)
2275                 {
2276                         v3s16 p = block->getPos()+v3s16(x,1,z);
2277                         lighting_update_blocks[p] = getBlockNoCreateNoEx(p);
2278                 }*/
2279 #endif
2280                 updateLighting(lighting_update_blocks, changed_blocks);
2281                 
2282                 /*
2283                         Set lighting to non-expired state in all of them.
2284                         This is cheating, but it is not fast enough if all of them
2285                         would actually be updated.
2286                 */
2287                 for(s16 x=-1; x<=1; x++)
2288                 for(s16 y=-1; y<=1; y++)
2289                 for(s16 z=-1; z<=1; z++)
2290                 {
2291                         v3s16 p = block->getPos()+v3s16(x,y,z);
2292                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2293                 }
2294
2295                 if(enable_mapgen_debug_info == false)
2296                         t.stop(true); // Hide output
2297         }
2298
2299         /*
2300                 Add random objects to block
2301         */
2302         mapgen::add_random_objects(block);
2303
2304         /*
2305                 Go through changed blocks
2306         */
2307         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2308                         i.atEnd() == false; i++)
2309         {
2310                 MapBlock *block = i.getNode()->getValue();
2311                 assert(block);
2312                 /*
2313                         Update day/night difference cache of the MapBlocks
2314                 */
2315                 block->updateDayNightDiff();
2316                 /*
2317                         Set block as modified
2318                 */
2319                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2320                                 "finishBlockMake updateDayNightDiff");
2321         }
2322
2323         /*
2324                 Set central block as generated
2325         */
2326         block->setGenerated(true);
2327         
2328         /*
2329                 Save changed parts of map
2330                 NOTE: Will be saved later.
2331         */
2332         //save(MOD_STATE_WRITE_AT_UNLOAD);
2333
2334         /*infostream<<"finishBlockMake() done for ("<<blockpos.X<<","<<blockpos.Y<<","
2335                         <<blockpos.Z<<")"<<std::endl;*/
2336 #if 0
2337         if(enable_mapgen_debug_info)
2338         {
2339                 /*
2340                         Analyze resulting blocks
2341                 */
2342                 for(s16 x=-1; x<=1; x++)
2343                 for(s16 y=-1; y<=1; y++)
2344                 for(s16 z=-1; z<=1; z++)
2345                 {
2346                         v3s16 p = block->getPos()+v3s16(x,y,z);
2347                         MapBlock *block = getBlockNoCreateNoEx(p);
2348                         char spos[20];
2349                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2350                         infostream<<"Generated "<<spos<<": "
2351                                         <<analyze_block(block)<<std::endl;
2352                 }
2353         }
2354 #endif
2355
2356         return block;
2357 }
2358
2359 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2360 {
2361         DSTACKF("%s: p2d=(%d,%d)",
2362                         __FUNCTION_NAME,
2363                         p2d.X, p2d.Y);
2364         
2365         /*
2366                 Check if it exists already in memory
2367         */
2368         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2369         if(sector != NULL)
2370                 return sector;
2371         
2372         /*
2373                 Try to load it from disk (with blocks)
2374         */
2375         //if(loadSectorFull(p2d) == true)
2376
2377         /*
2378                 Try to load metadata from disk
2379         */
2380 #if 0
2381         if(loadSectorMeta(p2d) == true)
2382         {
2383                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2384                 if(sector == NULL)
2385                 {
2386                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2387                         throw InvalidPositionException("");
2388                 }
2389                 return sector;
2390         }
2391 #endif
2392         /*
2393                 Do not create over-limit
2394         */
2395         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2396         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2397         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2398         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2399                 throw InvalidPositionException("createSector(): pos. over limit");
2400
2401         /*
2402                 Generate blank sector
2403         */
2404         
2405         sector = new ServerMapSector(this, p2d, m_gamedef);
2406         
2407         // Sector position on map in nodes
2408         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2409
2410         /*
2411                 Insert to container
2412         */
2413         m_sectors.insert(p2d, sector);
2414         
2415         return sector;
2416 }
2417
2418 /*
2419         This is a quick-hand function for calling makeBlock().
2420 */
2421 MapBlock * ServerMap::generateBlock(
2422                 v3s16 p,
2423                 core::map<v3s16, MapBlock*> &modified_blocks
2424 )
2425 {
2426         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2427         
2428         /*infostream<<"generateBlock(): "
2429                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2430                         <<std::endl;*/
2431         
2432         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2433
2434         TimeTaker timer("generateBlock");
2435         
2436         //MapBlock *block = original_dummy;
2437                         
2438         v2s16 p2d(p.X, p.Z);
2439         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2440         
2441         /*
2442                 Do not generate over-limit
2443         */
2444         if(blockpos_over_limit(p))
2445         {
2446                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2447                 throw InvalidPositionException("generateBlock(): pos. over limit");
2448         }
2449
2450         /*
2451                 Create block make data
2452         */
2453         mapgen::BlockMakeData data;
2454         initBlockMake(&data, p);
2455
2456         /*
2457                 Generate block
2458         */
2459         {
2460                 TimeTaker t("mapgen::make_block()");
2461                 mapgen::make_block(&data);
2462
2463                 if(enable_mapgen_debug_info == false)
2464                         t.stop(true); // Hide output
2465         }
2466
2467         /*
2468                 Blit data back on map, update lighting, add mobs and whatever this does
2469         */
2470         finishBlockMake(&data, modified_blocks);
2471
2472         /*
2473                 Get central block
2474         */
2475         MapBlock *block = getBlockNoCreateNoEx(p);
2476
2477 #if 0
2478         /*
2479                 Check result
2480         */
2481         if(block)
2482         {
2483                 bool erroneus_content = false;
2484                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2485                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2486                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2487                 {
2488                         v3s16 p(x0,y0,z0);
2489                         MapNode n = block->getNode(p);
2490                         if(n.getContent() == CONTENT_IGNORE)
2491                         {
2492                                 infostream<<"CONTENT_IGNORE at "
2493                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2494                                                 <<std::endl;
2495                                 erroneus_content = true;
2496                                 assert(0);
2497                         }
2498                 }
2499                 if(erroneus_content)
2500                 {
2501                         assert(0);
2502                 }
2503         }
2504 #endif
2505
2506 #if 0
2507         /*
2508                 Generate a completely empty block
2509         */
2510         if(block)
2511         {
2512                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2513                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2514                 {
2515                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2516                         {
2517                                 MapNode n;
2518                                 n.setContent(CONTENT_AIR);
2519                                 block->setNode(v3s16(x0,y0,z0), n);
2520                         }
2521                 }
2522         }
2523 #endif
2524
2525         if(enable_mapgen_debug_info == false)
2526                 timer.stop(true); // Hide output
2527
2528         return block;
2529 }
2530
2531 MapBlock * ServerMap::createBlock(v3s16 p)
2532 {
2533         DSTACKF("%s: p=(%d,%d,%d)",
2534                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2535         
2536         /*
2537                 Do not create over-limit
2538         */
2539         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2540         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2541         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2542         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2543         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2544         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2545                 throw InvalidPositionException("createBlock(): pos. over limit");
2546         
2547         v2s16 p2d(p.X, p.Z);
2548         s16 block_y = p.Y;
2549         /*
2550                 This will create or load a sector if not found in memory.
2551                 If block exists on disk, it will be loaded.
2552
2553                 NOTE: On old save formats, this will be slow, as it generates
2554                       lighting on blocks for them.
2555         */
2556         ServerMapSector *sector;
2557         try{
2558                 sector = (ServerMapSector*)createSector(p2d);
2559                 assert(sector->getId() == MAPSECTOR_SERVER);
2560         }
2561         catch(InvalidPositionException &e)
2562         {
2563                 infostream<<"createBlock: createSector() failed"<<std::endl;
2564                 throw e;
2565         }
2566         /*
2567                 NOTE: This should not be done, or at least the exception
2568                 should not be passed on as std::exception, because it
2569                 won't be catched at all.
2570         */
2571         /*catch(std::exception &e)
2572         {
2573                 infostream<<"createBlock: createSector() failed: "
2574                                 <<e.what()<<std::endl;
2575                 throw e;
2576         }*/
2577
2578         /*
2579                 Try to get a block from the sector
2580         */
2581
2582         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2583         if(block)
2584         {
2585                 if(block->isDummy())
2586                         block->unDummify();
2587                 return block;
2588         }
2589         // Create blank
2590         block = sector->createBlankBlock(block_y);
2591         return block;
2592 }
2593
2594 MapBlock * ServerMap::emergeBlock(v3s16 p, bool allow_generate)
2595 {
2596         DSTACKF("%s: p=(%d,%d,%d), allow_generate=%d",
2597                         __FUNCTION_NAME,
2598                         p.X, p.Y, p.Z, allow_generate);
2599         
2600         {
2601                 MapBlock *block = getBlockNoCreateNoEx(p);
2602                 if(block && block->isDummy() == false)
2603                         return block;
2604         }
2605
2606         {
2607                 MapBlock *block = loadBlock(p);
2608                 if(block)
2609                         return block;
2610         }
2611
2612         if(allow_generate)
2613         {
2614                 core::map<v3s16, MapBlock*> modified_blocks;
2615                 MapBlock *block = generateBlock(p, modified_blocks);
2616                 if(block)
2617                 {
2618                         MapEditEvent event;
2619                         event.type = MEET_OTHER;
2620                         event.p = p;
2621
2622                         // Copy modified_blocks to event
2623                         for(core::map<v3s16, MapBlock*>::Iterator
2624                                         i = modified_blocks.getIterator();
2625                                         i.atEnd()==false; i++)
2626                         {
2627                                 event.modified_blocks.insert(i.getNode()->getKey(), false);
2628                         }
2629
2630                         // Queue event
2631                         dispatchEvent(&event);
2632                                                                 
2633                         return block;
2634                 }
2635         }
2636
2637         return NULL;
2638 }
2639
2640 s16 ServerMap::findGroundLevel(v2s16 p2d)
2641 {
2642 #if 0
2643         /*
2644                 Uh, just do something random...
2645         */
2646         // Find existing map from top to down
2647         s16 max=63;
2648         s16 min=-64;
2649         v3s16 p(p2d.X, max, p2d.Y);
2650         for(; p.Y>min; p.Y--)
2651         {
2652                 MapNode n = getNodeNoEx(p);
2653                 if(n.getContent() != CONTENT_IGNORE)
2654                         break;
2655         }
2656         if(p.Y == min)
2657                 goto plan_b;
2658         // If this node is not air, go to plan b
2659         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2660                 goto plan_b;
2661         // Search existing walkable and return it
2662         for(; p.Y>min; p.Y--)
2663         {
2664                 MapNode n = getNodeNoEx(p);
2665                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2666                         return p.Y;
2667         }
2668
2669         // Move to plan b
2670 plan_b:
2671 #endif
2672
2673         /*
2674                 Determine from map generator noise functions
2675         */
2676         
2677         s16 level = mapgen::find_ground_level_from_noise(m_seed, p2d, 1);
2678         return level;
2679
2680         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2681         //return (s16)level;
2682 }
2683
2684 void ServerMap::createDatabase() {
2685         int e;
2686         assert(m_database);
2687         e = sqlite3_exec(m_database,
2688                 "CREATE TABLE IF NOT EXISTS `blocks` ("
2689                         "`pos` INT NOT NULL PRIMARY KEY,"
2690                         "`data` BLOB"
2691                 ");"
2692         , NULL, NULL, NULL);
2693         if(e == SQLITE_ABORT)
2694                 throw FileNotGoodException("Could not create database structure");
2695         else
2696                 infostream<<"Server: Database structure was created";
2697 }
2698
2699 void ServerMap::verifyDatabase() {
2700         if(m_database)
2701                 return;
2702         
2703         {
2704                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
2705                 bool needs_create = false;
2706                 int d;
2707                 
2708                 /*
2709                         Open the database connection
2710                 */
2711         
2712                 createDirs(m_savedir);
2713         
2714                 if(!fs::PathExists(dbp))
2715                         needs_create = true;
2716         
2717                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
2718                 if(d != SQLITE_OK) {
2719                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
2720                         throw FileNotGoodException("Cannot open database file");
2721                 }
2722                 
2723                 if(needs_create)
2724                         createDatabase();
2725         
2726                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
2727                 if(d != SQLITE_OK) {
2728                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2729                         throw FileNotGoodException("Cannot prepare read statement");
2730                 }
2731                 
2732                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
2733                 if(d != SQLITE_OK) {
2734                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2735                         throw FileNotGoodException("Cannot prepare write statement");
2736                 }
2737                 
2738                 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
2739                 if(d != SQLITE_OK) {
2740                         infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2741                         throw FileNotGoodException("Cannot prepare read statement");
2742                 }
2743                 
2744                 infostream<<"Server: Database opened"<<std::endl;
2745         }
2746 }
2747
2748 bool ServerMap::loadFromFolders() {
2749         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2750                 return true;
2751         return false;
2752 }
2753
2754 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
2755         return (sqlite3_int64)pos.Z*16777216 +
2756                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
2757 }
2758
2759 void ServerMap::createDirs(std::string path)
2760 {
2761         if(fs::CreateAllDirs(path) == false)
2762         {
2763                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2764                                 <<"\""<<path<<"\""<<std::endl;
2765                 throw BaseException("ServerMap failed to create directory");
2766         }
2767 }
2768
2769 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2770 {
2771         char cc[9];
2772         switch(layout)
2773         {
2774                 case 1:
2775                         snprintf(cc, 9, "%.4x%.4x",
2776                                 (unsigned int)pos.X&0xffff,
2777                                 (unsigned int)pos.Y&0xffff);
2778
2779                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2780                 case 2:
2781                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2782                                 (unsigned int)pos.X&0xfff,
2783                                 (unsigned int)pos.Y&0xfff);
2784
2785                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2786                 default:
2787                         assert(false);
2788         }
2789 }
2790
2791 v2s16 ServerMap::getSectorPos(std::string dirname)
2792 {
2793         unsigned int x, y;
2794         int r;
2795         size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
2796         assert(spos != std::string::npos);
2797         if(dirname.size() - spos == 8)
2798         {
2799                 // Old layout
2800                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2801         }
2802         else if(dirname.size() - spos == 3)
2803         {
2804                 // New layout
2805                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2806                 // Sign-extend the 12 bit values up to 16 bits...
2807                 if(x&0x800) x|=0xF000;
2808                 if(y&0x800) y|=0xF000;
2809         }
2810         else
2811         {
2812                 assert(false);
2813         }
2814         assert(r == 2);
2815         v2s16 pos((s16)x, (s16)y);
2816         return pos;
2817 }
2818
2819 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2820 {
2821         v2s16 p2d = getSectorPos(sectordir);
2822
2823         if(blockfile.size() != 4){
2824                 throw InvalidFilenameException("Invalid block filename");
2825         }
2826         unsigned int y;
2827         int r = sscanf(blockfile.c_str(), "%4x", &y);
2828         if(r != 1)
2829                 throw InvalidFilenameException("Invalid block filename");
2830         return v3s16(p2d.X, y, p2d.Y);
2831 }
2832
2833 std::string ServerMap::getBlockFilename(v3s16 p)
2834 {
2835         char cc[5];
2836         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2837         return cc;
2838 }
2839
2840 void ServerMap::save(ModifiedState save_level)
2841 {
2842         DSTACK(__FUNCTION_NAME);
2843         if(m_map_saving_enabled == false)
2844         {
2845                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2846                 return;
2847         }
2848         
2849         if(save_level == MOD_STATE_CLEAN)
2850                 infostream<<"ServerMap: Saving whole map, this can take time."
2851                                 <<std::endl;
2852         
2853         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
2854         {
2855                 saveMapMeta();
2856         }
2857
2858         // Profile modified reasons
2859         Profiler modprofiler;
2860         
2861         u32 sector_meta_count = 0;
2862         u32 block_count = 0;
2863         u32 block_count_all = 0; // Number of blocks in memory
2864         
2865         // Don't do anything with sqlite unless something is really saved
2866         bool save_started = false;
2867
2868         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2869         for(; i.atEnd() == false; i++)
2870         {
2871                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2872                 assert(sector->getId() == MAPSECTOR_SERVER);
2873         
2874                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
2875                 {
2876                         saveSectorMeta(sector);
2877                         sector_meta_count++;
2878                 }
2879                 core::list<MapBlock*> blocks;
2880                 sector->getBlocks(blocks);
2881                 core::list<MapBlock*>::Iterator j;
2882                 
2883                 for(j=blocks.begin(); j!=blocks.end(); j++)
2884                 {
2885                         MapBlock *block = *j;
2886                         
2887                         block_count_all++;
2888
2889                         if(block->getModified() >= save_level)
2890                         {
2891                                 // Lazy beginSave()
2892                                 if(!save_started){
2893                                         beginSave();
2894                                         save_started = true;
2895                                 }
2896
2897                                 modprofiler.add(block->getModifiedReason(), 1);
2898
2899                                 saveBlock(block);
2900                                 block_count++;
2901
2902                                 /*infostream<<"ServerMap: Written block ("
2903                                                 <<block->getPos().X<<","
2904                                                 <<block->getPos().Y<<","
2905                                                 <<block->getPos().Z<<")"
2906                                                 <<std::endl;*/
2907                         }
2908                 }
2909         }
2910         if(save_started)
2911                 endSave();
2912
2913         /*
2914                 Only print if something happened or saved whole map
2915         */
2916         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
2917                         || block_count != 0)
2918         {
2919                 infostream<<"ServerMap: Written: "
2920                                 <<sector_meta_count<<" sector metadata files, "
2921                                 <<block_count<<" block files"
2922                                 <<", "<<block_count_all<<" blocks in memory."
2923                                 <<std::endl;
2924                 PrintInfo(infostream); // ServerMap/ClientMap:
2925                 infostream<<"Blocks modified by: "<<std::endl;
2926                 modprofiler.print(infostream);
2927         }
2928 }
2929
2930 static s32 unsignedToSigned(s32 i, s32 max_positive)
2931 {
2932         if(i < max_positive)
2933                 return i;
2934         else
2935                 return i - 2*max_positive;
2936 }
2937
2938 // modulo of a negative number does not work consistently in C
2939 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
2940 {
2941         if(i >= 0)
2942                 return i % mod;
2943         return mod - ((-i) % mod);
2944 }
2945
2946 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
2947 {
2948         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2949         i = (i - x) / 4096;
2950         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2951         i = (i - y) / 4096;
2952         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
2953         return v3s16(x,y,z);
2954 }
2955
2956 void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
2957 {
2958         if(loadFromFolders()){
2959                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
2960                                 <<"all blocks that are stored in flat files"<<std::endl;
2961         }
2962         
2963         {
2964                 verifyDatabase();
2965                 
2966                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
2967                 {
2968                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
2969                         v3s16 p = getIntegerAsBlock(block_i);
2970                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
2971                         dst.push_back(p);
2972                 }
2973         }
2974 }
2975
2976 void ServerMap::saveMapMeta()
2977 {
2978         DSTACK(__FUNCTION_NAME);
2979         
2980         infostream<<"ServerMap::saveMapMeta(): "
2981                         <<"seed="<<m_seed
2982                         <<std::endl;
2983
2984         createDirs(m_savedir);
2985         
2986         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
2987         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
2988         if(os.good() == false)
2989         {
2990                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
2991                                 <<"could not open"<<fullpath<<std::endl;
2992                 throw FileNotGoodException("Cannot open chunk metadata");
2993         }
2994         
2995         Settings params;
2996         params.setU64("seed", m_seed);
2997
2998         params.writeLines(os);
2999
3000         os<<"[end_of_params]\n";
3001         
3002         m_map_metadata_changed = false;
3003 }
3004
3005 void ServerMap::loadMapMeta()
3006 {
3007         DSTACK(__FUNCTION_NAME);
3008         
3009         infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3010                         <<std::endl;
3011
3012         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3013         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3014         if(is.good() == false)
3015         {
3016                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3017                                 <<"could not open"<<fullpath<<std::endl;
3018                 throw FileNotGoodException("Cannot open map metadata");
3019         }
3020
3021         Settings params;
3022
3023         for(;;)
3024         {
3025                 if(is.eof())
3026                         throw SerializationError
3027                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3028                 std::string line;
3029                 std::getline(is, line);
3030                 std::string trimmedline = trim(line);
3031                 if(trimmedline == "[end_of_params]")
3032                         break;
3033                 params.parseConfigLine(line);
3034         }
3035
3036         m_seed = params.getU64("seed");
3037
3038         infostream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3039 }
3040
3041 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3042 {
3043         DSTACK(__FUNCTION_NAME);
3044         // Format used for writing
3045         u8 version = SER_FMT_VER_HIGHEST;
3046         // Get destination
3047         v2s16 pos = sector->getPos();
3048         std::string dir = getSectorDir(pos);
3049         createDirs(dir);
3050         
3051         std::string fullpath = dir + DIR_DELIM + "meta";
3052         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3053         if(o.good() == false)
3054                 throw FileNotGoodException("Cannot open sector metafile");
3055
3056         sector->serialize(o, version);
3057         
3058         sector->differs_from_disk = false;
3059 }
3060
3061 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3062 {
3063         DSTACK(__FUNCTION_NAME);
3064         // Get destination
3065         v2s16 p2d = getSectorPos(sectordir);
3066
3067         ServerMapSector *sector = NULL;
3068
3069         std::string fullpath = sectordir + DIR_DELIM + "meta";
3070         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3071         if(is.good() == false)
3072         {
3073                 // If the directory exists anyway, it probably is in some old
3074                 // format. Just go ahead and create the sector.
3075                 if(fs::PathExists(sectordir))
3076                 {
3077                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3078                                         <<fullpath<<" doesn't exist but directory does."
3079                                         <<" Continuing with a sector with no metadata."
3080                                         <<std::endl;*/
3081                         sector = new ServerMapSector(this, p2d, m_gamedef);
3082                         m_sectors.insert(p2d, sector);
3083                 }
3084                 else
3085                 {
3086                         throw FileNotGoodException("Cannot open sector metafile");
3087                 }
3088         }
3089         else
3090         {
3091                 sector = ServerMapSector::deSerialize
3092                                 (is, this, p2d, m_sectors, m_gamedef);
3093                 if(save_after_load)
3094                         saveSectorMeta(sector);
3095         }
3096         
3097         sector->differs_from_disk = false;
3098
3099         return sector;
3100 }
3101
3102 bool ServerMap::loadSectorMeta(v2s16 p2d)
3103 {
3104         DSTACK(__FUNCTION_NAME);
3105
3106         MapSector *sector = NULL;
3107
3108         // The directory layout we're going to load from.
3109         //  1 - original sectors/xxxxzzzz/
3110         //  2 - new sectors2/xxx/zzz/
3111         //  If we load from anything but the latest structure, we will
3112         //  immediately save to the new one, and remove the old.
3113         int loadlayout = 1;
3114         std::string sectordir1 = getSectorDir(p2d, 1);
3115         std::string sectordir;
3116         if(fs::PathExists(sectordir1))
3117         {
3118                 sectordir = sectordir1;
3119         }
3120         else
3121         {
3122                 loadlayout = 2;
3123                 sectordir = getSectorDir(p2d, 2);
3124         }
3125
3126         try{
3127                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3128         }
3129         catch(InvalidFilenameException &e)
3130         {
3131                 return false;
3132         }
3133         catch(FileNotGoodException &e)
3134         {
3135                 return false;
3136         }
3137         catch(std::exception &e)
3138         {
3139                 return false;
3140         }
3141         
3142         return true;
3143 }
3144
3145 #if 0
3146 bool ServerMap::loadSectorFull(v2s16 p2d)
3147 {
3148         DSTACK(__FUNCTION_NAME);
3149
3150         MapSector *sector = NULL;
3151
3152         // The directory layout we're going to load from.
3153         //  1 - original sectors/xxxxzzzz/
3154         //  2 - new sectors2/xxx/zzz/
3155         //  If we load from anything but the latest structure, we will
3156         //  immediately save to the new one, and remove the old.
3157         int loadlayout = 1;
3158         std::string sectordir1 = getSectorDir(p2d, 1);
3159         std::string sectordir;
3160         if(fs::PathExists(sectordir1))
3161         {
3162                 sectordir = sectordir1;
3163         }
3164         else
3165         {
3166                 loadlayout = 2;
3167                 sectordir = getSectorDir(p2d, 2);
3168         }
3169
3170         try{
3171                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3172         }
3173         catch(InvalidFilenameException &e)
3174         {
3175                 return false;
3176         }
3177         catch(FileNotGoodException &e)
3178         {
3179                 return false;
3180         }
3181         catch(std::exception &e)
3182         {
3183                 return false;
3184         }
3185         
3186         /*
3187                 Load blocks
3188         */
3189         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3190                         (sectordir);
3191         std::vector<fs::DirListNode>::iterator i2;
3192         for(i2=list2.begin(); i2!=list2.end(); i2++)
3193         {
3194                 // We want files
3195                 if(i2->dir)
3196                         continue;
3197                 try{
3198                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3199                 }
3200                 catch(InvalidFilenameException &e)
3201                 {
3202                         // This catches unknown crap in directory
3203                 }
3204         }
3205
3206         if(loadlayout != 2)
3207         {
3208                 infostream<<"Sector converted to new layout - deleting "<<
3209                         sectordir1<<std::endl;
3210                 fs::RecursiveDelete(sectordir1);
3211         }
3212
3213         return true;
3214 }
3215 #endif
3216
3217 void ServerMap::beginSave() {
3218         verifyDatabase();
3219         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3220                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3221 }
3222
3223 void ServerMap::endSave() {
3224         verifyDatabase();
3225         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3226                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3227 }
3228
3229 void ServerMap::saveBlock(MapBlock *block)
3230 {
3231         DSTACK(__FUNCTION_NAME);
3232         /*
3233                 Dummy blocks are not written
3234         */
3235         if(block->isDummy())
3236         {
3237                 /*v3s16 p = block->getPos();
3238                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3239                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3240                 return;
3241         }
3242
3243         // Format used for writing
3244         u8 version = SER_FMT_VER_HIGHEST;
3245         // Get destination
3246         v3s16 p3d = block->getPos();
3247         
3248         
3249 #if 0
3250         v2s16 p2d(p3d.X, p3d.Z);
3251         std::string sectordir = getSectorDir(p2d);
3252
3253         createDirs(sectordir);
3254
3255         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3256         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3257         if(o.good() == false)
3258                 throw FileNotGoodException("Cannot open block data");
3259 #endif
3260         /*
3261                 [0] u8 serialization version
3262                 [1] data
3263         */
3264         
3265         verifyDatabase();
3266         
3267         std::ostringstream o(std::ios_base::binary);
3268         
3269         o.write((char*)&version, 1);
3270         
3271         // Write basic data
3272         block->serialize(o, version);
3273         
3274         // Write extra data stored on disk
3275         block->serializeDiskExtra(o, version);
3276         
3277         // Write block to database
3278         
3279         std::string tmp = o.str();
3280         const char *bytes = tmp.c_str();
3281         
3282         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK)
3283                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3284         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) // TODO this mught not be the right length
3285                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3286         int written = sqlite3_step(m_database_write);
3287         if(written != SQLITE_DONE)
3288                 infostream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3289                 <<sqlite3_errmsg(m_database)<<std::endl;
3290         // Make ready for later reuse
3291         sqlite3_reset(m_database_write);
3292         
3293         // We just wrote it to the disk so clear modified flag
3294         block->resetModified();
3295 }
3296
3297 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3298 {
3299         DSTACK(__FUNCTION_NAME);
3300
3301         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3302         try{
3303
3304                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3305                 if(is.good() == false)
3306                         throw FileNotGoodException("Cannot open block file");
3307                 
3308                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3309                 v2s16 p2d(p3d.X, p3d.Z);
3310                 
3311                 assert(sector->getPos() == p2d);
3312                 
3313                 u8 version = SER_FMT_VER_INVALID;
3314                 is.read((char*)&version, 1);
3315
3316                 if(is.fail())
3317                         throw SerializationError("ServerMap::loadBlock(): Failed"
3318                                         " to read MapBlock version");
3319
3320                 /*u32 block_size = MapBlock::serializedLength(version);
3321                 SharedBuffer<u8> data(block_size);
3322                 is.read((char*)*data, block_size);*/
3323
3324                 // This will always return a sector because we're the server
3325                 //MapSector *sector = emergeSector(p2d);
3326
3327                 MapBlock *block = NULL;
3328                 bool created_new = false;
3329                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3330                 if(block == NULL)
3331                 {
3332                         block = sector->createBlankBlockNoInsert(p3d.Y);
3333                         created_new = true;
3334                 }
3335                 
3336                 // Read basic data
3337                 block->deSerialize(is, version);
3338
3339                 // Read extra data stored on disk
3340                 block->deSerializeDiskExtra(is, version);
3341                 
3342                 // If it's a new block, insert it to the map
3343                 if(created_new)
3344                         sector->insertBlock(block);
3345                 
3346                 /*
3347                         Save blocks loaded in old format in new format
3348                 */
3349
3350                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3351                 {
3352                         saveBlock(block);
3353                         
3354                         // Should be in database now, so delete the old file
3355                         fs::RecursiveDelete(fullpath);
3356                 }
3357                 
3358                 // We just loaded it from the disk, so it's up-to-date.
3359                 block->resetModified();
3360
3361         }
3362         catch(SerializationError &e)
3363         {
3364                 infostream<<"WARNING: Invalid block data on disk "
3365                                 <<"fullpath="<<fullpath
3366                                 <<" (SerializationError). "
3367                                 <<"what()="<<e.what()
3368                                 <<std::endl;
3369                                 //" Ignoring. A new one will be generated.
3370                 assert(0);
3371
3372                 // TODO: Backup file; name is in fullpath.
3373         }
3374 }
3375
3376 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3377 {
3378         DSTACK(__FUNCTION_NAME);
3379
3380         try {
3381                 std::istringstream is(*blob, std::ios_base::binary);
3382                 
3383                 u8 version = SER_FMT_VER_INVALID;
3384                 is.read((char*)&version, 1);
3385
3386                 if(is.fail())
3387                         throw SerializationError("ServerMap::loadBlock(): Failed"
3388                                         " to read MapBlock version");
3389
3390                 /*u32 block_size = MapBlock::serializedLength(version);
3391                 SharedBuffer<u8> data(block_size);
3392                 is.read((char*)*data, block_size);*/
3393
3394                 // This will always return a sector because we're the server
3395                 //MapSector *sector = emergeSector(p2d);
3396
3397                 MapBlock *block = NULL;
3398                 bool created_new = false;
3399                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3400                 if(block == NULL)
3401                 {
3402                         block = sector->createBlankBlockNoInsert(p3d.Y);
3403                         created_new = true;
3404                 }
3405                 
3406                 // Read basic data
3407                 block->deSerialize(is, version);
3408
3409                 // Read extra data stored on disk
3410                 block->deSerializeDiskExtra(is, version);
3411                 
3412                 // If it's a new block, insert it to the map
3413                 if(created_new)
3414                         sector->insertBlock(block);
3415                 
3416                 /*
3417                         Save blocks loaded in old format in new format
3418                 */
3419
3420                 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
3421                 // Only save if asked to; no need to update version
3422                 if(save_after_load)
3423                         saveBlock(block);
3424                 
3425                 // We just loaded it from, so it's up-to-date.
3426                 block->resetModified();
3427
3428         }
3429         catch(SerializationError &e)
3430         {
3431                 infostream<<"WARNING: Invalid block data in database "
3432                                 <<" (SerializationError). "
3433                                 <<"what()="<<e.what()
3434                                 <<std::endl;
3435                                 //" Ignoring. A new one will be generated.
3436                 assert(0);
3437
3438                 // TODO: Copy to a backup database.
3439         }
3440 }
3441
3442 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3443 {
3444         DSTACK(__FUNCTION_NAME);
3445
3446         v2s16 p2d(blockpos.X, blockpos.Z);
3447
3448         if(!loadFromFolders()) {
3449                 verifyDatabase();
3450                 
3451                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3452                         infostream<<"WARNING: Could not bind block position for load: "
3453                                 <<sqlite3_errmsg(m_database)<<std::endl;
3454                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3455                         /*
3456                                 Make sure sector is loaded
3457                         */
3458                         MapSector *sector = createSector(p2d);
3459                         
3460                         /*
3461                                 Load block
3462                         */
3463                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3464                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3465                         
3466                         std::string datastr(data, len);
3467                         
3468                         loadBlock(&datastr, blockpos, sector, false);
3469
3470                         sqlite3_step(m_database_read);
3471                         // We should never get more than 1 row, so ok to reset
3472                         sqlite3_reset(m_database_read);
3473
3474                         return getBlockNoCreateNoEx(blockpos);
3475                 }
3476                 sqlite3_reset(m_database_read);
3477                 
3478                 // Not found in database, try the files
3479         }
3480
3481         // The directory layout we're going to load from.
3482         //  1 - original sectors/xxxxzzzz/
3483         //  2 - new sectors2/xxx/zzz/
3484         //  If we load from anything but the latest structure, we will
3485         //  immediately save to the new one, and remove the old.
3486         int loadlayout = 1;
3487         std::string sectordir1 = getSectorDir(p2d, 1);
3488         std::string sectordir;
3489         if(fs::PathExists(sectordir1))
3490         {
3491                 sectordir = sectordir1;
3492         }
3493         else
3494         {
3495                 loadlayout = 2;
3496                 sectordir = getSectorDir(p2d, 2);
3497         }
3498         
3499         /*
3500                 Make sure sector is loaded
3501         */
3502         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3503         if(sector == NULL)
3504         {
3505                 try{
3506                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3507                 }
3508                 catch(InvalidFilenameException &e)
3509                 {
3510                         return false;
3511                 }
3512                 catch(FileNotGoodException &e)
3513                 {
3514                         return false;
3515                 }
3516                 catch(std::exception &e)
3517                 {
3518                         return false;
3519                 }
3520         }
3521         
3522         /*
3523                 Make sure file exists
3524         */
3525
3526         std::string blockfilename = getBlockFilename(blockpos);
3527         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3528                 return NULL;
3529
3530         /*
3531                 Load block and save it to the database
3532         */
3533         loadBlock(sectordir, blockfilename, sector, true);
3534         return getBlockNoCreateNoEx(blockpos);
3535 }
3536
3537 void ServerMap::PrintInfo(std::ostream &out)
3538 {
3539         out<<"ServerMap: ";
3540 }
3541
3542 #ifndef SERVER
3543
3544 /*
3545         ClientMap
3546 */
3547
3548 ClientMap::ClientMap(
3549                 Client *client,
3550                 IGameDef *gamedef,
3551                 MapDrawControl &control,
3552                 scene::ISceneNode* parent,
3553                 scene::ISceneManager* mgr,
3554                 s32 id
3555 ):
3556         Map(dout_client, gamedef),
3557         scene::ISceneNode(parent, mgr, id),
3558         m_client(client),
3559         m_control(control),
3560         m_camera_position(0,0,0),
3561         m_camera_direction(0,0,1),
3562         m_camera_fov(PI)
3563 {
3564         m_camera_mutex.Init();
3565         assert(m_camera_mutex.IsInitialized());
3566         
3567         m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
3568                         BS*1000000,BS*1000000,BS*1000000);
3569 }
3570
3571 ClientMap::~ClientMap()
3572 {
3573         /*JMutexAutoLock lock(mesh_mutex);
3574         
3575         if(mesh != NULL)
3576         {
3577                 mesh->drop();
3578                 mesh = NULL;
3579         }*/
3580 }
3581
3582 MapSector * ClientMap::emergeSector(v2s16 p2d)
3583 {
3584         DSTACK(__FUNCTION_NAME);
3585         // Check that it doesn't exist already
3586         try{
3587                 return getSectorNoGenerate(p2d);
3588         }
3589         catch(InvalidPositionException &e)
3590         {
3591         }
3592         
3593         // Create a sector
3594         ClientMapSector *sector = new ClientMapSector(this, p2d, m_gamedef);
3595         
3596         {
3597                 //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3598                 m_sectors.insert(p2d, sector);
3599         }
3600         
3601         return sector;
3602 }
3603
3604 #if 0
3605 void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
3606 {
3607         DSTACK(__FUNCTION_NAME);
3608         ClientMapSector *sector = NULL;
3609
3610         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3611         
3612         core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
3613
3614         if(n != NULL)
3615         {
3616                 sector = (ClientMapSector*)n->getValue();
3617                 assert(sector->getId() == MAPSECTOR_CLIENT);
3618         }
3619         else
3620         {
3621                 sector = new ClientMapSector(this, p2d);
3622                 {
3623                         //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
3624                         m_sectors.insert(p2d, sector);
3625                 }
3626         }
3627
3628         sector->deSerialize(is);
3629 }
3630 #endif
3631
3632 void ClientMap::OnRegisterSceneNode()
3633 {
3634         if(IsVisible)
3635         {
3636                 SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
3637                 SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT);
3638         }
3639
3640         ISceneNode::OnRegisterSceneNode();
3641 }
3642
3643 static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac,
3644                 float start_off, float end_off, u32 needed_count, INodeDefManager *nodemgr)
3645 {
3646         float d0 = (float)BS * p0.getDistanceFrom(p1);
3647         v3s16 u0 = p1 - p0;
3648         v3f uf = v3f(u0.X, u0.Y, u0.Z) * BS;
3649         uf.normalize();
3650         v3f p0f = v3f(p0.X, p0.Y, p0.Z) * BS;
3651         u32 count = 0;
3652         for(float s=start_off; s<d0+end_off; s+=step){
3653                 v3f pf = p0f + uf * s;
3654                 v3s16 p = floatToInt(pf, BS);
3655                 MapNode n = map->getNodeNoEx(p);
3656                 bool is_transparent = false;
3657                 const ContentFeatures &f = nodemgr->get(n);
3658                 if(f.solidness == 0)
3659                         is_transparent = (f.visual_solidness != 2);
3660                 else
3661                         is_transparent = (f.solidness != 2);
3662                 if(!is_transparent){
3663                         count++;
3664                         if(count >= needed_count)
3665                                 return true;
3666                 }
3667                 step *= stepfac;
3668         }
3669         return false;
3670 }
3671
3672 void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
3673 {
3674         INodeDefManager *nodemgr = m_gamedef->ndef();
3675
3676         //m_dout<<DTIME<<"Rendering map..."<<std::endl;
3677         DSTACK(__FUNCTION_NAME);
3678
3679         bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
3680         
3681         std::string prefix;
3682         if(pass == scene::ESNRP_SOLID)
3683                 prefix = "CM: solid: ";
3684         else
3685                 prefix = "CM: transparent: ";
3686
3687         /*
3688                 This is called two times per frame, reset on the non-transparent one
3689         */
3690         if(pass == scene::ESNRP_SOLID)
3691         {
3692                 m_last_drawn_sectors.clear();
3693         }
3694
3695         /*
3696                 Get time for measuring timeout.
3697                 
3698                 Measuring time is very useful for long delays when the
3699                 machine is swapping a lot.
3700         */
3701         int time1 = time(0);
3702
3703         //u32 daynight_ratio = m_client->getDayNightRatio();
3704
3705         m_camera_mutex.Lock();
3706         v3f camera_position = m_camera_position;
3707         v3f camera_direction = m_camera_direction;
3708         f32 camera_fov = m_camera_fov;
3709         m_camera_mutex.Unlock();
3710
3711         /*
3712                 Get all blocks and draw all visible ones
3713         */
3714
3715         v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
3716         
3717         v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
3718
3719         v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
3720         v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
3721
3722         // Take a fair amount as we will be dropping more out later
3723         // Umm... these additions are a bit strange but they are needed.
3724         v3s16 p_blocks_min(
3725                         p_nodes_min.X / MAP_BLOCKSIZE - 3,
3726                         p_nodes_min.Y / MAP_BLOCKSIZE - 3,
3727                         p_nodes_min.Z / MAP_BLOCKSIZE - 3);
3728         v3s16 p_blocks_max(
3729                         p_nodes_max.X / MAP_BLOCKSIZE + 1,
3730                         p_nodes_max.Y / MAP_BLOCKSIZE + 1,
3731                         p_nodes_max.Z / MAP_BLOCKSIZE + 1);
3732         
3733         u32 vertex_count = 0;
3734         u32 meshbuffer_count = 0;
3735         
3736         // For limiting number of mesh updates per frame
3737         u32 mesh_update_count = 0;
3738         
3739         // Number of blocks in rendering range
3740         u32 blocks_in_range = 0;
3741         // Number of blocks occlusion culled
3742         u32 blocks_occlusion_culled = 0;
3743         // Number of blocks in rendering range but don't have a mesh
3744         u32 blocks_in_range_without_mesh = 0;
3745         // Blocks that had mesh that would have been drawn according to
3746         // rendering range (if max blocks limit didn't kick in)
3747         u32 blocks_would_have_drawn = 0;
3748         // Blocks that were drawn and had a mesh
3749         u32 blocks_drawn = 0;
3750         // Blocks which had a corresponding meshbuffer for this pass
3751         u32 blocks_had_pass_meshbuf = 0;
3752         // Blocks from which stuff was actually drawn
3753         u32 blocks_without_stuff = 0;
3754
3755         /*
3756                 Collect a set of blocks for drawing
3757         */
3758         
3759         core::map<v3s16, MapBlock*> drawset;
3760
3761         {
3762         ScopeProfiler sp(g_profiler, prefix+"collecting blocks for drawing", SPT_AVG);
3763
3764         for(core::map<v2s16, MapSector*>::Iterator
3765                         si = m_sectors.getIterator();
3766                         si.atEnd() == false; si++)
3767         {
3768                 MapSector *sector = si.getNode()->getValue();
3769                 v2s16 sp = sector->getPos();
3770                 
3771                 if(m_control.range_all == false)
3772                 {
3773                         if(sp.X < p_blocks_min.X
3774                         || sp.X > p_blocks_max.X
3775                         || sp.Y < p_blocks_min.Z
3776                         || sp.Y > p_blocks_max.Z)
3777                                 continue;
3778                 }
3779
3780                 core::list< MapBlock * > sectorblocks;
3781                 sector->getBlocks(sectorblocks);
3782                 
3783                 /*
3784                         Loop through blocks in sector
3785                 */
3786
3787                 u32 sector_blocks_drawn = 0;
3788                 
3789                 core::list< MapBlock * >::Iterator i;
3790                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
3791                 {
3792                         MapBlock *block = *i;
3793
3794                         /*
3795                                 Compare block position to camera position, skip
3796                                 if not seen on display
3797                         */
3798                         
3799                         float range = 100000 * BS;
3800                         if(m_control.range_all == false)
3801                                 range = m_control.wanted_range * BS;
3802
3803                         float d = 0.0;
3804                         if(isBlockInSight(block->getPos(), camera_position,
3805                                         camera_direction, camera_fov,
3806                                         range, &d) == false)
3807                         {
3808                                 continue;
3809                         }
3810
3811                         // This is ugly (spherical distance limit?)
3812                         /*if(m_control.range_all == false &&
3813                                         d - 0.5*BS*MAP_BLOCKSIZE > range)
3814                                 continue;*/
3815
3816                         blocks_in_range++;
3817                         
3818 #if 1
3819                         /*
3820                                 Update expired mesh (used for day/night change)
3821
3822                                 It doesn't work exactly like it should now with the
3823                                 tasked mesh update but whatever.
3824                         */
3825
3826                         bool mesh_expired = false;
3827                         
3828                         {
3829                                 JMutexAutoLock lock(block->mesh_mutex);
3830
3831                                 mesh_expired = block->getMeshExpired();
3832
3833                                 // Mesh has not been expired and there is no mesh:
3834                                 // block has no content
3835                                 if(block->mesh == NULL && mesh_expired == false){
3836                                         blocks_in_range_without_mesh++;
3837                                         continue;
3838                                 }
3839                         }
3840
3841                         f32 faraway = BS*50;
3842                         //f32 faraway = m_control.wanted_range * BS;
3843                         
3844                         /*
3845                                 This has to be done with the mesh_mutex unlocked
3846                         */
3847                         // Pretty random but this should work somewhat nicely
3848                         if(mesh_expired && (
3849                                         (mesh_update_count < 3
3850                                                 && (d < faraway || mesh_update_count < 2)
3851                                         )
3852                                         || 
3853                                         (m_control.range_all && mesh_update_count < 20)
3854                                 )
3855                         )
3856                         /*if(mesh_expired && mesh_update_count < 6
3857                                         && (d < faraway || mesh_update_count < 3))*/
3858                         {
3859                                 mesh_update_count++;
3860
3861                                 // Mesh has been expired: generate new mesh
3862                                 //block->updateMesh(daynight_ratio);
3863                                 m_client->addUpdateMeshTask(block->getPos());
3864
3865                                 mesh_expired = false;
3866                         }
3867 #endif
3868
3869                         /*
3870                                 Occlusion culling
3871                         */
3872
3873                         v3s16 cpn = block->getPos() * MAP_BLOCKSIZE;
3874                         cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);
3875                         float step = BS*1;
3876                         float stepfac = 1.1;
3877                         float startoff = BS*1;
3878                         float endoff = -BS*MAP_BLOCKSIZE*1.42*1.42;
3879                         v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
3880                         s16 bs2 = MAP_BLOCKSIZE/2 + 1;
3881                         u32 needed_count = 1;
3882                         if(
3883                                 isOccluded(this, spn, cpn + v3s16(0,0,0),
3884                                         step, stepfac, startoff, endoff, needed_count, nodemgr) &&
3885                                 isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
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                         )
3902                         {
3903                                 blocks_occlusion_culled++;
3904                                 continue;
3905                         }
3906                         
3907                         // This block is in range. Reset usage timer.
3908                         block->resetUsageTimer();
3909
3910                         /*
3911                                 Ignore if mesh doesn't exist
3912                         */
3913                         {
3914                                 JMutexAutoLock lock(block->mesh_mutex);
3915
3916                                 scene::SMesh *mesh = block->mesh;
3917                                 
3918                                 if(mesh == NULL){
3919                                         blocks_in_range_without_mesh++;
3920                                         continue;
3921                                 }
3922                         }
3923                         
3924                         // Limit block count in case of a sudden increase
3925                         blocks_would_have_drawn++;
3926                         if(blocks_drawn >= m_control.wanted_max_blocks
3927                                         && m_control.range_all == false
3928                                         && d > m_control.wanted_min_range * BS)
3929                                 continue;
3930                         
3931                         // Add to set
3932                         drawset[block->getPos()] = block;
3933                         
3934                         sector_blocks_drawn++;
3935                         blocks_drawn++;
3936
3937                 } // foreach sectorblocks
3938
3939                 if(sector_blocks_drawn != 0)
3940                         m_last_drawn_sectors[sp] = true;
3941         }
3942         } // ScopeProfiler
3943         
3944         /*
3945                 Draw the selected MapBlocks
3946         */
3947
3948         {
3949         ScopeProfiler sp(g_profiler, prefix+"drawing blocks", SPT_AVG);
3950
3951         int timecheck_counter = 0;
3952         for(core::map<v3s16, MapBlock*>::Iterator
3953                         i = drawset.getIterator();
3954                         i.atEnd() == false; i++)
3955         {
3956                 {
3957                         timecheck_counter++;
3958                         if(timecheck_counter > 50)
3959                         {
3960                                 timecheck_counter = 0;
3961                                 int time2 = time(0);
3962                                 if(time2 > time1 + 4)
3963                                 {
3964                                         infostream<<"ClientMap::renderMap(): "
3965                                                 "Rendering takes ages, returning."
3966                                                 <<std::endl;
3967                                         return;
3968                                 }
3969                         }
3970                 }
3971                 
3972                 MapBlock *block = i.getNode()->getValue();
3973
3974                 /*
3975                         Draw the faces of the block
3976                 */
3977                 {
3978                         JMutexAutoLock lock(block->mesh_mutex);
3979
3980                         scene::SMesh *mesh = block->mesh;
3981                         assert(mesh);
3982                         
3983                         u32 c = mesh->getMeshBufferCount();
3984                         bool stuff_actually_drawn = false;
3985                         for(u32 i=0; i<c; i++)
3986                         {
3987                                 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
3988                                 const video::SMaterial& material = buf->getMaterial();
3989                                 video::IMaterialRenderer* rnd =
3990                                                 driver->getMaterialRenderer(material.MaterialType);
3991                                 bool transparent = (rnd && rnd->isTransparent());
3992                                 // Render transparent on transparent pass and likewise.
3993                                 if(transparent == is_transparent_pass)
3994                                 {
3995                                         if(buf->getVertexCount() == 0)
3996                                                 errorstream<<"Block ["<<analyze_block(block)
3997                                                                 <<"] contains an empty meshbuf"<<std::endl;
3998                                         /*
3999                                                 This *shouldn't* hurt too much because Irrlicht
4000                                                 doesn't change opengl textures if the old
4001                                                 material has the same texture.
4002                                         */
4003                                         driver->setMaterial(buf->getMaterial());
4004                                         driver->drawMeshBuffer(buf);
4005                                         vertex_count += buf->getVertexCount();
4006                                         meshbuffer_count++;
4007                                         stuff_actually_drawn = true;
4008                                 }
4009                         }
4010                         if(stuff_actually_drawn)
4011                                 blocks_had_pass_meshbuf++;
4012                         else
4013                                 blocks_without_stuff++;
4014                 }
4015         }
4016         } // ScopeProfiler
4017         
4018         // Log only on solid pass because values are the same
4019         if(pass == scene::ESNRP_SOLID){
4020                 g_profiler->avg("CM: blocks in range", blocks_in_range);
4021                 g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
4022                 if(blocks_in_range != 0)
4023                         g_profiler->avg("CM: blocks in range without mesh (frac)",
4024                                         (float)blocks_in_range_without_mesh/blocks_in_range);
4025                 g_profiler->avg("CM: blocks drawn", blocks_drawn);
4026         }
4027         
4028         g_profiler->avg(prefix+"vertices drawn", vertex_count);
4029         if(blocks_had_pass_meshbuf != 0)
4030                 g_profiler->avg(prefix+"meshbuffers per block",
4031                                 (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
4032         if(blocks_drawn != 0)
4033                 g_profiler->avg(prefix+"empty blocks (frac)",
4034                                 (float)blocks_without_stuff / blocks_drawn);
4035
4036         m_control.blocks_drawn = blocks_drawn;
4037         m_control.blocks_would_have_drawn = blocks_would_have_drawn;
4038
4039         /*infostream<<"renderMap(): is_transparent_pass="<<is_transparent_pass
4040                         <<", rendered "<<vertex_count<<" vertices."<<std::endl;*/
4041 }
4042
4043 void ClientMap::renderPostFx()
4044 {
4045         INodeDefManager *nodemgr = m_gamedef->ndef();
4046
4047         // Sadly ISceneManager has no "post effects" render pass, in that case we
4048         // could just register for that and handle it in renderMap().
4049
4050         m_camera_mutex.Lock();
4051         v3f camera_position = m_camera_position;
4052         m_camera_mutex.Unlock();
4053
4054         MapNode n = getNodeNoEx(floatToInt(camera_position, BS));
4055
4056         // - If the player is in a solid node, make everything black.
4057         // - If the player is in liquid, draw a semi-transparent overlay.
4058         const ContentFeatures& features = nodemgr->get(n);
4059         video::SColor post_effect_color = features.post_effect_color;
4060         if(features.solidness == 2 && g_settings->getBool("free_move") == false)
4061         {
4062                 post_effect_color = video::SColor(255, 0, 0, 0);
4063         }
4064         if (post_effect_color.getAlpha() != 0)
4065         {
4066                 // Draw a full-screen rectangle
4067                 video::IVideoDriver* driver = SceneManager->getVideoDriver();
4068                 v2u32 ss = driver->getScreenSize();
4069                 core::rect<s32> rect(0,0, ss.X, ss.Y);
4070                 driver->draw2DRectangle(post_effect_color, rect);
4071         }
4072 }
4073
4074 bool ClientMap::setTempMod(v3s16 p, NodeMod mod,
4075                 core::map<v3s16, MapBlock*> *affected_blocks)
4076 {
4077         bool changed = false;
4078         /*
4079                 Add it to all blocks touching it
4080         */
4081         v3s16 dirs[7] = {
4082                 v3s16(0,0,0), // this
4083                 v3s16(0,0,1), // back
4084                 v3s16(0,1,0), // top
4085                 v3s16(1,0,0), // right
4086                 v3s16(0,0,-1), // front
4087                 v3s16(0,-1,0), // bottom
4088                 v3s16(-1,0,0), // left
4089         };
4090         for(u16 i=0; i<7; i++)
4091         {
4092                 v3s16 p2 = p + dirs[i];
4093                 // Block position of neighbor (or requested) node
4094                 v3s16 blockpos = getNodeBlockPos(p2);
4095                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4096                 if(blockref == NULL)
4097                         continue;
4098                 // Relative position of requested node
4099                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4100                 if(blockref->setTempMod(relpos, mod))
4101                 {
4102                         changed = true;
4103                 }
4104         }
4105         if(changed && affected_blocks!=NULL)
4106         {
4107                 for(u16 i=0; i<7; i++)
4108                 {
4109                         v3s16 p2 = p + dirs[i];
4110                         // Block position of neighbor (or requested) node
4111                         v3s16 blockpos = getNodeBlockPos(p2);
4112                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4113                         if(blockref == NULL)
4114                                 continue;
4115                         affected_blocks->insert(blockpos, blockref);
4116                 }
4117         }
4118         return changed;
4119 }
4120
4121 bool ClientMap::clearTempMod(v3s16 p,
4122                 core::map<v3s16, MapBlock*> *affected_blocks)
4123 {
4124         bool changed = false;
4125         v3s16 dirs[7] = {
4126                 v3s16(0,0,0), // this
4127                 v3s16(0,0,1), // back
4128                 v3s16(0,1,0), // top
4129                 v3s16(1,0,0), // right
4130                 v3s16(0,0,-1), // front
4131                 v3s16(0,-1,0), // bottom
4132                 v3s16(-1,0,0), // left
4133         };
4134         for(u16 i=0; i<7; i++)
4135         {
4136                 v3s16 p2 = p + dirs[i];
4137                 // Block position of neighbor (or requested) node
4138                 v3s16 blockpos = getNodeBlockPos(p2);
4139                 MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4140                 if(blockref == NULL)
4141                         continue;
4142                 // Relative position of requested node
4143                 v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
4144                 if(blockref->clearTempMod(relpos))
4145                 {
4146                         changed = true;
4147                 }
4148         }
4149         if(changed && affected_blocks!=NULL)
4150         {
4151                 for(u16 i=0; i<7; i++)
4152                 {
4153                         v3s16 p2 = p + dirs[i];
4154                         // Block position of neighbor (or requested) node
4155                         v3s16 blockpos = getNodeBlockPos(p2);
4156                         MapBlock * blockref = getBlockNoCreateNoEx(blockpos);
4157                         if(blockref == NULL)
4158                                 continue;
4159                         affected_blocks->insert(blockpos, blockref);
4160                 }
4161         }
4162         return changed;
4163 }
4164
4165 void ClientMap::expireMeshes(bool only_daynight_diffed)
4166 {
4167         TimeTaker timer("expireMeshes()");
4168
4169         core::map<v2s16, MapSector*>::Iterator si;
4170         si = m_sectors.getIterator();
4171         for(; si.atEnd() == false; si++)
4172         {
4173                 MapSector *sector = si.getNode()->getValue();
4174
4175                 core::list< MapBlock * > sectorblocks;
4176                 sector->getBlocks(sectorblocks);
4177                 
4178                 core::list< MapBlock * >::Iterator i;
4179                 for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
4180                 {
4181                         MapBlock *block = *i;
4182
4183                         if(only_daynight_diffed && dayNightDiffed(block->getPos()) == false)
4184                         {
4185                                 continue;
4186                         }
4187                         
4188                         {
4189                                 JMutexAutoLock lock(block->mesh_mutex);
4190                                 if(block->mesh != NULL)
4191                                 {
4192                                         /*block->mesh->drop();
4193                                         block->mesh = NULL;*/
4194                                         block->setMeshExpired(true);
4195                                 }
4196                         }
4197                 }
4198         }
4199 }
4200
4201 void ClientMap::updateMeshes(v3s16 blockpos, u32 daynight_ratio)
4202 {
4203         assert(mapType() == MAPTYPE_CLIENT);
4204
4205         try{
4206                 v3s16 p = blockpos + v3s16(0,0,0);
4207                 MapBlock *b = getBlockNoCreate(p);
4208                 b->updateMesh(daynight_ratio);
4209                 //b->setMeshExpired(true);
4210         }
4211         catch(InvalidPositionException &e){}
4212         // Leading edge
4213         try{
4214                 v3s16 p = blockpos + v3s16(-1,0,0);
4215                 MapBlock *b = getBlockNoCreate(p);
4216                 b->updateMesh(daynight_ratio);
4217                 //b->setMeshExpired(true);
4218         }
4219         catch(InvalidPositionException &e){}
4220         try{
4221                 v3s16 p = blockpos + v3s16(0,-1,0);
4222                 MapBlock *b = getBlockNoCreate(p);
4223                 b->updateMesh(daynight_ratio);
4224                 //b->setMeshExpired(true);
4225         }
4226         catch(InvalidPositionException &e){}
4227         try{
4228                 v3s16 p = blockpos + v3s16(0,0,-1);
4229                 MapBlock *b = getBlockNoCreate(p);
4230                 b->updateMesh(daynight_ratio);
4231                 //b->setMeshExpired(true);
4232         }
4233         catch(InvalidPositionException &e){}
4234 }
4235
4236 #if 0
4237 /*
4238         Update mesh of block in which the node is, and if the node is at the
4239         leading edge, update the appropriate leading blocks too.
4240 */
4241 void ClientMap::updateNodeMeshes(v3s16 nodepos, u32 daynight_ratio)
4242 {
4243         v3s16 dirs[4] = {
4244                 v3s16(0,0,0),
4245                 v3s16(-1,0,0),
4246                 v3s16(0,-1,0),
4247                 v3s16(0,0,-1),
4248         };
4249         v3s16 blockposes[4];
4250         for(u32 i=0; i<4; i++)
4251         {
4252                 v3s16 np = nodepos + dirs[i];
4253                 blockposes[i] = getNodeBlockPos(np);
4254                 // Don't update mesh of block if it has been done already
4255                 bool already_updated = false;
4256                 for(u32 j=0; j<i; j++)
4257                 {
4258                         if(blockposes[j] == blockposes[i])
4259                         {
4260                                 already_updated = true;
4261                                 break;
4262                         }
4263                 }
4264                 if(already_updated)
4265                         continue;
4266                 // Update mesh
4267                 MapBlock *b = getBlockNoCreate(blockposes[i]);
4268                 b->updateMesh(daynight_ratio);
4269         }
4270 }
4271 #endif
4272
4273 void ClientMap::PrintInfo(std::ostream &out)
4274 {
4275         out<<"ClientMap: ";
4276 }
4277
4278 #endif // !SERVER
4279
4280 /*
4281         MapVoxelManipulator
4282 */
4283
4284 MapVoxelManipulator::MapVoxelManipulator(Map *map)
4285 {
4286         m_map = map;
4287 }
4288
4289 MapVoxelManipulator::~MapVoxelManipulator()
4290 {
4291         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4292                         <<std::endl;*/
4293 }
4294
4295 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4296 {
4297         TimeTaker timer1("emerge", &emerge_time);
4298
4299         // Units of these are MapBlocks
4300         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4301         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4302
4303         VoxelArea block_area_nodes
4304                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4305
4306         addArea(block_area_nodes);
4307
4308         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4309         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4310         for(s32 x=p_min.X; x<=p_max.X; x++)
4311         {
4312                 v3s16 p(x,y,z);
4313                 core::map<v3s16, bool>::Node *n;
4314                 n = m_loaded_blocks.find(p);
4315                 if(n != NULL)
4316                         continue;
4317                 
4318                 bool block_data_inexistent = false;
4319                 try
4320                 {
4321                         TimeTaker timer1("emerge load", &emerge_load_time);
4322
4323                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4324                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4325                                         <<" wanted area: ";
4326                         a.print(infostream);
4327                         infostream<<std::endl;*/
4328                         
4329                         MapBlock *block = m_map->getBlockNoCreate(p);
4330                         if(block->isDummy())
4331                                 block_data_inexistent = true;
4332                         else
4333                                 block->copyTo(*this);
4334                 }
4335                 catch(InvalidPositionException &e)
4336                 {
4337                         block_data_inexistent = true;
4338                 }
4339
4340                 if(block_data_inexistent)
4341                 {
4342                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4343                         // Fill with VOXELFLAG_INEXISTENT
4344                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4345                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4346                         {
4347                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4348                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4349                         }
4350                 }
4351
4352                 m_loaded_blocks.insert(p, !block_data_inexistent);
4353         }
4354
4355         //infostream<<"emerge done"<<std::endl;
4356 }
4357
4358 /*
4359         SUGG: Add an option to only update eg. water and air nodes.
4360               This will make it interfere less with important stuff if
4361                   run on background.
4362 */
4363 void MapVoxelManipulator::blitBack
4364                 (core::map<v3s16, MapBlock*> & modified_blocks)
4365 {
4366         if(m_area.getExtent() == v3s16(0,0,0))
4367                 return;
4368         
4369         //TimeTaker timer1("blitBack");
4370
4371         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4372                         <<m_loaded_blocks.size()<<std::endl;*/
4373         
4374         /*
4375                 Initialize block cache
4376         */
4377         v3s16 blockpos_last;
4378         MapBlock *block = NULL;
4379         bool block_checked_in_modified = false;
4380
4381         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4382         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4383         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4384         {
4385                 v3s16 p(x,y,z);
4386
4387                 u8 f = m_flags[m_area.index(p)];
4388                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4389                         continue;
4390
4391                 MapNode &n = m_data[m_area.index(p)];
4392                         
4393                 v3s16 blockpos = getNodeBlockPos(p);
4394                 
4395                 try
4396                 {
4397                         // Get block
4398                         if(block == NULL || blockpos != blockpos_last){
4399                                 block = m_map->getBlockNoCreate(blockpos);
4400                                 blockpos_last = blockpos;
4401                                 block_checked_in_modified = false;
4402                         }
4403                         
4404                         // Calculate relative position in block
4405                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4406
4407                         // Don't continue if nothing has changed here
4408                         if(block->getNode(relpos) == n)
4409                                 continue;
4410
4411                         //m_map->setNode(m_area.MinEdge + p, n);
4412                         block->setNode(relpos, n);
4413                         
4414                         /*
4415                                 Make sure block is in modified_blocks
4416                         */
4417                         if(block_checked_in_modified == false)
4418                         {
4419                                 modified_blocks[blockpos] = block;
4420                                 block_checked_in_modified = true;
4421                         }
4422                 }
4423                 catch(InvalidPositionException &e)
4424                 {
4425                 }
4426         }
4427 }
4428
4429 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4430                 MapVoxelManipulator(map),
4431                 m_create_area(false)
4432 {
4433 }
4434
4435 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4436 {
4437 }
4438
4439 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4440 {
4441         // Just create the area so that it can be pointed to
4442         VoxelManipulator::emerge(a, caller_id);
4443 }
4444
4445 void ManualMapVoxelManipulator::initialEmerge(
4446                 v3s16 blockpos_min, v3s16 blockpos_max)
4447 {
4448         TimeTaker timer1("initialEmerge", &emerge_time);
4449
4450         // Units of these are MapBlocks
4451         v3s16 p_min = blockpos_min;
4452         v3s16 p_max = blockpos_max;
4453
4454         VoxelArea block_area_nodes
4455                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4456         
4457         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4458         if(size_MB >= 1)
4459         {
4460                 infostream<<"initialEmerge: area: ";
4461                 block_area_nodes.print(infostream);
4462                 infostream<<" ("<<size_MB<<"MB)";
4463                 infostream<<std::endl;
4464         }
4465
4466         addArea(block_area_nodes);
4467
4468         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4469         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4470         for(s32 x=p_min.X; x<=p_max.X; x++)
4471         {
4472                 v3s16 p(x,y,z);
4473                 core::map<v3s16, bool>::Node *n;
4474                 n = m_loaded_blocks.find(p);
4475                 if(n != NULL)
4476                         continue;
4477                 
4478                 bool block_data_inexistent = false;
4479                 try
4480                 {
4481                         TimeTaker timer1("emerge load", &emerge_load_time);
4482
4483                         MapBlock *block = m_map->getBlockNoCreate(p);
4484                         if(block->isDummy())
4485                                 block_data_inexistent = true;
4486                         else
4487                                 block->copyTo(*this);
4488                 }
4489                 catch(InvalidPositionException &e)
4490                 {
4491                         block_data_inexistent = true;
4492                 }
4493
4494                 if(block_data_inexistent)
4495                 {
4496                         /*
4497                                 Mark area inexistent
4498                         */
4499                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4500                         // Fill with VOXELFLAG_INEXISTENT
4501                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4502                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4503                         {
4504                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4505                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4506                         }
4507                 }
4508
4509                 m_loaded_blocks.insert(p, !block_data_inexistent);
4510         }
4511 }
4512
4513 void ManualMapVoxelManipulator::blitBackAll(
4514                 core::map<v3s16, MapBlock*> * modified_blocks)
4515 {
4516         if(m_area.getExtent() == v3s16(0,0,0))
4517                 return;
4518         
4519         /*
4520                 Copy data of all blocks
4521         */
4522         for(core::map<v3s16, bool>::Iterator
4523                         i = m_loaded_blocks.getIterator();
4524                         i.atEnd() == false; i++)
4525         {
4526                 v3s16 p = i.getNode()->getKey();
4527                 bool existed = i.getNode()->getValue();
4528                 if(existed == false)
4529                 {
4530                         // The Great Bug was found using this
4531                         /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
4532                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4533                                         <<std::endl;*/
4534                         continue;
4535                 }
4536                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4537                 if(block == NULL)
4538                 {
4539                         infostream<<"WARNING: "<<__FUNCTION_NAME
4540                                         <<": got NULL block "
4541                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4542                                         <<std::endl;
4543                         continue;
4544                 }
4545
4546                 block->copyFrom(*this);
4547
4548                 if(modified_blocks)
4549                         modified_blocks->insert(p, block);
4550         }
4551 }
4552
4553 //END