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