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