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