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