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