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