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