]> git.lizzy.rs Git - dragonfireclient.git/blob - src/map.cpp
Bunch of small fixes (coding style, very unlikely errors, warning messages)
[dragonfireclient.git] / src / map.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 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 Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser 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 "filesys.h"
25 #include "voxel.h"
26 #include "porting.h"
27 #include "serialization.h"
28 #include "nodemetadata.h"
29 #include "settings.h"
30 #include "log.h"
31 #include "profiler.h"
32 #include "nodedef.h"
33 #include "gamedef.h"
34 #include "util/directiontables.h"
35 #include "util/mathconstants.h"
36 #include "rollback_interface.h"
37 #include "environment.h"
38 #include "emerge.h"
39 #include "mapgen_v6.h"
40 #include "biome.h"
41 #include "config.h"
42 #include "server.h"
43 #include "database.h"
44 #include "database-dummy.h"
45 #include "database-sqlite3.h"
46 #if USE_LEVELDB
47 #include "database-leveldb.h"
48 #endif
49 #if USE_REDIS
50 #include "database-redis.h"
51 #endif
52
53 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
54
55 /*
56         SQLite format specification:
57         - Initially only replaces sectors/ and sectors2/
58
59         If map.sqlite does not exist in the save dir
60         or the block was not found in the database
61         the map will try to load from sectors folder.
62         In either case, map.sqlite will be created
63         and all future saves will save there.
64
65         Structure of map.sqlite:
66         Tables:
67                 blocks
68                         (PK) INT pos
69                         BLOB data
70 */
71
72 /*
73         Map
74 */
75
76 Map::Map(std::ostream &dout, IGameDef *gamedef):
77         m_dout(dout),
78         m_gamedef(gamedef),
79         m_sector_cache(NULL)
80 {
81 }
82
83 Map::~Map()
84 {
85         /*
86                 Free all MapSectors
87         */
88         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
89                 i != m_sectors.end(); ++i)
90         {
91                 delete i->second;
92         }
93 }
94
95 void Map::addEventReceiver(MapEventReceiver *event_receiver)
96 {
97         m_event_receivers.insert(event_receiver);
98 }
99
100 void Map::removeEventReceiver(MapEventReceiver *event_receiver)
101 {
102         m_event_receivers.erase(event_receiver);
103 }
104
105 void Map::dispatchEvent(MapEditEvent *event)
106 {
107         for(std::set<MapEventReceiver*>::iterator
108                         i = m_event_receivers.begin();
109                         i != m_event_receivers.end(); ++i)
110         {
111                 (*i)->onMapEditEvent(event);
112         }
113 }
114
115 MapSector * Map::getSectorNoGenerateNoExNoLock(v2s16 p)
116 {
117         if(m_sector_cache != NULL && p == m_sector_cache_p){
118                 MapSector * sector = m_sector_cache;
119                 return sector;
120         }
121
122         std::map<v2s16, MapSector*>::iterator n = m_sectors.find(p);
123
124         if(n == m_sectors.end())
125                 return NULL;
126
127         MapSector *sector = n->second;
128
129         // Cache the last result
130         m_sector_cache_p = p;
131         m_sector_cache = sector;
132
133         return sector;
134 }
135
136 MapSector * Map::getSectorNoGenerateNoEx(v2s16 p)
137 {
138         return getSectorNoGenerateNoExNoLock(p);
139 }
140
141 MapSector * Map::getSectorNoGenerate(v2s16 p)
142 {
143         MapSector *sector = getSectorNoGenerateNoEx(p);
144         if(sector == NULL)
145                 throw InvalidPositionException();
146
147         return sector;
148 }
149
150 MapBlock * Map::getBlockNoCreateNoEx(v3s16 p3d)
151 {
152         v2s16 p2d(p3d.X, p3d.Z);
153         MapSector * sector = getSectorNoGenerateNoEx(p2d);
154         if(sector == NULL)
155                 return NULL;
156         MapBlock *block = sector->getBlockNoCreateNoEx(p3d.Y);
157         return block;
158 }
159
160 MapBlock * Map::getBlockNoCreate(v3s16 p3d)
161 {
162         MapBlock *block = getBlockNoCreateNoEx(p3d);
163         if(block == NULL)
164                 throw InvalidPositionException();
165         return block;
166 }
167
168 bool Map::isNodeUnderground(v3s16 p)
169 {
170         v3s16 blockpos = getNodeBlockPos(p);
171         try{
172                 MapBlock * block = getBlockNoCreate(blockpos);
173                 return block->getIsUnderground();
174         }
175         catch(InvalidPositionException &e)
176         {
177                 return false;
178         }
179 }
180
181 bool Map::isValidPosition(v3s16 p)
182 {
183         v3s16 blockpos = getNodeBlockPos(p);
184         MapBlock *block = getBlockNoCreate(blockpos);
185         return (block != NULL);
186 }
187
188 // Returns a CONTENT_IGNORE node if not found
189 MapNode Map::getNodeNoEx(v3s16 p)
190 {
191         v3s16 blockpos = getNodeBlockPos(p);
192         MapBlock *block = getBlockNoCreateNoEx(blockpos);
193         if(block == NULL)
194                 return MapNode(CONTENT_IGNORE);
195         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
196         return block->getNodeNoCheck(relpos);
197 }
198
199 // throws InvalidPositionException if not found
200 MapNode Map::getNode(v3s16 p)
201 {
202         v3s16 blockpos = getNodeBlockPos(p);
203         MapBlock *block = getBlockNoCreateNoEx(blockpos);
204         if(block == NULL)
205                 throw InvalidPositionException();
206         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
207         return block->getNodeNoCheck(relpos);
208 }
209
210 // throws InvalidPositionException if not found
211 void Map::setNode(v3s16 p, MapNode & n)
212 {
213         v3s16 blockpos = getNodeBlockPos(p);
214         MapBlock *block = getBlockNoCreate(blockpos);
215         v3s16 relpos = p - blockpos*MAP_BLOCKSIZE;
216         // Never allow placing CONTENT_IGNORE, it fucks up stuff
217         if(n.getContent() == CONTENT_IGNORE){
218                 errorstream<<"Map::setNode(): Not allowing to place CONTENT_IGNORE"
219                                 <<" while trying to replace \""
220                                 <<m_gamedef->ndef()->get(block->getNodeNoCheck(relpos)).name
221                                 <<"\" at "<<PP(p)<<" (block "<<PP(blockpos)<<")"<<std::endl;
222                 debug_stacks_print_to(infostream);
223                 return;
224         }
225         block->setNodeNoCheck(relpos, n);
226 }
227
228
229 /*
230         Goes recursively through the neighbours of the node.
231
232         Alters only transparent nodes.
233
234         If the lighting of the neighbour is lower than the lighting of
235         the node was (before changing it to 0 at the step before), the
236         lighting of the neighbour is set to 0 and then the same stuff
237         repeats for the neighbour.
238
239         The ending nodes of the routine are stored in light_sources.
240         This is useful when a light is removed. In such case, this
241         routine can be called for the light node and then again for
242         light_sources to re-light the area without the removed light.
243
244         values of from_nodes are lighting values.
245 */
246 void Map::unspreadLight(enum LightBank bank,
247                 std::map<v3s16, u8> & from_nodes,
248                 std::set<v3s16> & light_sources,
249                 std::map<v3s16, MapBlock*>  & modified_blocks)
250 {
251         INodeDefManager *nodemgr = m_gamedef->ndef();
252
253         v3s16 dirs[6] = {
254                 v3s16(0,0,1), // back
255                 v3s16(0,1,0), // top
256                 v3s16(1,0,0), // right
257                 v3s16(0,0,-1), // front
258                 v3s16(0,-1,0), // bottom
259                 v3s16(-1,0,0), // left
260         };
261
262         if(from_nodes.size() == 0)
263                 return;
264
265         u32 blockchangecount = 0;
266
267         std::map<v3s16, u8> unlighted_nodes;
268
269         /*
270                 Initialize block cache
271         */
272         v3s16 blockpos_last;
273         MapBlock *block = NULL;
274         // Cache this a bit, too
275         bool block_checked_in_modified = false;
276
277         for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
278                 j != from_nodes.end(); ++j)
279         {
280                 v3s16 pos = j->first;
281                 v3s16 blockpos = getNodeBlockPos(pos);
282
283                 // Only fetch a new block if the block position has changed
284                 try{
285                         if(block == NULL || blockpos != blockpos_last){
286                                 block = getBlockNoCreate(blockpos);
287                                 blockpos_last = blockpos;
288
289                                 block_checked_in_modified = false;
290                                 blockchangecount++;
291                         }
292                 }
293                 catch(InvalidPositionException &e)
294                 {
295                         continue;
296                 }
297
298                 if(block->isDummy())
299                         continue;
300
301                 // Calculate relative position in block
302                 //v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
303
304                 // Get node straight from the block
305                 //MapNode n = block->getNode(relpos);
306
307                 u8 oldlight = j->second;
308
309                 // Loop through 6 neighbors
310                 for(u16 i=0; i<6; i++)
311                 {
312                         // Get the position of the neighbor node
313                         v3s16 n2pos = pos + dirs[i];
314
315                         // Get the block where the node is located
316                         v3s16 blockpos = getNodeBlockPos(n2pos);
317
318                         try
319                         {
320                                 // Only fetch a new block if the block position has changed
321                                 try{
322                                         if(block == NULL || blockpos != blockpos_last){
323                                                 block = getBlockNoCreate(blockpos);
324                                                 blockpos_last = blockpos;
325
326                                                 block_checked_in_modified = false;
327                                                 blockchangecount++;
328                                         }
329                                 }
330                                 catch(InvalidPositionException &e)
331                                 {
332                                         continue;
333                                 }
334
335                                 // Calculate relative position in block
336                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
337                                 // Get node straight from the block
338                                 MapNode n2 = block->getNode(relpos);
339
340                                 bool changed = false;
341
342                                 //TODO: Optimize output by optimizing light_sources?
343
344                                 /*
345                                         If the neighbor is dimmer than what was specified
346                                         as oldlight (the light of the previous node)
347                                 */
348                                 if(n2.getLight(bank, nodemgr) < oldlight)
349                                 {
350                                         /*
351                                                 And the neighbor is transparent and it has some light
352                                         */
353                                         if(nodemgr->get(n2).light_propagates
354                                                         && n2.getLight(bank, nodemgr) != 0)
355                                         {
356                                                 /*
357                                                         Set light to 0 and add to queue
358                                                 */
359
360                                                 u8 current_light = n2.getLight(bank, nodemgr);
361                                                 n2.setLight(bank, 0, nodemgr);
362                                                 block->setNode(relpos, n2);
363
364                                                 unlighted_nodes[n2pos] = current_light;
365                                                 changed = true;
366
367                                                 /*
368                                                         Remove from light_sources if it is there
369                                                         NOTE: This doesn't happen nearly at all
370                                                 */
371                                                 /*if(light_sources.find(n2pos))
372                                                 {
373                                                         infostream<<"Removed from light_sources"<<std::endl;
374                                                         light_sources.remove(n2pos);
375                                                 }*/
376                                         }
377
378                                         /*// DEBUG
379                                         if(light_sources.find(n2pos) != NULL)
380                                                 light_sources.remove(n2pos);*/
381                                 }
382                                 else{
383                                         light_sources.insert(n2pos);
384                                 }
385
386                                 // Add to modified_blocks
387                                 if(changed == true && block_checked_in_modified == false)
388                                 {
389                                         // If the block is not found in modified_blocks, add.
390                                         if(modified_blocks.find(blockpos) == modified_blocks.end())
391                                         {
392                                                 modified_blocks[blockpos] = block;
393                                         }
394                                         block_checked_in_modified = true;
395                                 }
396                         }
397                         catch(InvalidPositionException &e)
398                         {
399                                 continue;
400                         }
401                 }
402         }
403
404         /*infostream<<"unspreadLight(): Changed block "
405                         <<blockchangecount<<" times"
406                         <<" for "<<from_nodes.size()<<" nodes"
407                         <<std::endl;*/
408
409         if(unlighted_nodes.size() > 0)
410                 unspreadLight(bank, unlighted_nodes, light_sources, modified_blocks);
411 }
412
413 /*
414         A single-node wrapper of the above
415 */
416 void Map::unLightNeighbors(enum LightBank bank,
417                 v3s16 pos, u8 lightwas,
418                 std::set<v3s16> & light_sources,
419                 std::map<v3s16, MapBlock*>  & modified_blocks)
420 {
421         std::map<v3s16, u8> from_nodes;
422         from_nodes[pos] = lightwas;
423
424         unspreadLight(bank, from_nodes, light_sources, modified_blocks);
425 }
426
427 /*
428         Lights neighbors of from_nodes, collects all them and then
429         goes on recursively.
430 */
431 void Map::spreadLight(enum LightBank bank,
432                 std::set<v3s16> & from_nodes,
433                 std::map<v3s16, MapBlock*> & modified_blocks)
434 {
435         INodeDefManager *nodemgr = m_gamedef->ndef();
436
437         const v3s16 dirs[6] = {
438                 v3s16(0,0,1), // back
439                 v3s16(0,1,0), // top
440                 v3s16(1,0,0), // right
441                 v3s16(0,0,-1), // front
442                 v3s16(0,-1,0), // bottom
443                 v3s16(-1,0,0), // left
444         };
445
446         if(from_nodes.size() == 0)
447                 return;
448
449         u32 blockchangecount = 0;
450
451         std::set<v3s16> lighted_nodes;
452
453         /*
454                 Initialize block cache
455         */
456         v3s16 blockpos_last;
457         MapBlock *block = NULL;
458         // Cache this a bit, too
459         bool block_checked_in_modified = false;
460
461         for(std::set<v3s16>::iterator j = from_nodes.begin();
462                 j != from_nodes.end(); ++j)
463         {
464                 v3s16 pos = *j;
465                 v3s16 blockpos = getNodeBlockPos(pos);
466
467                 // Only fetch a new block if the block position has changed
468                 try{
469                         if(block == NULL || blockpos != blockpos_last){
470                                 block = getBlockNoCreate(blockpos);
471                                 blockpos_last = blockpos;
472
473                                 block_checked_in_modified = false;
474                                 blockchangecount++;
475                         }
476                 }
477                 catch(InvalidPositionException &e)
478                 {
479                         continue;
480                 }
481
482                 if(block->isDummy())
483                         continue;
484
485                 // Calculate relative position in block
486                 v3s16 relpos = pos - blockpos_last * MAP_BLOCKSIZE;
487
488                 // Get node straight from the block
489                 MapNode n = block->getNode(relpos);
490
491                 u8 oldlight = n.getLight(bank, nodemgr);
492                 u8 newlight = diminish_light(oldlight);
493
494                 // Loop through 6 neighbors
495                 for(u16 i=0; i<6; i++){
496                         // Get the position of the neighbor node
497                         v3s16 n2pos = pos + dirs[i];
498
499                         // Get the block where the node is located
500                         v3s16 blockpos = getNodeBlockPos(n2pos);
501
502                         try
503                         {
504                                 // Only fetch a new block if the block position has changed
505                                 try{
506                                         if(block == NULL || blockpos != blockpos_last){
507                                                 block = getBlockNoCreate(blockpos);
508                                                 blockpos_last = blockpos;
509
510                                                 block_checked_in_modified = false;
511                                                 blockchangecount++;
512                                         }
513                                 }
514                                 catch(InvalidPositionException &e)
515                                 {
516                                         continue;
517                                 }
518
519                                 // Calculate relative position in block
520                                 v3s16 relpos = n2pos - blockpos * MAP_BLOCKSIZE;
521                                 // Get node straight from the block
522                                 MapNode n2 = block->getNode(relpos);
523
524                                 bool changed = false;
525                                 /*
526                                         If the neighbor is brighter than the current node,
527                                         add to list (it will light up this node on its turn)
528                                 */
529                                 if(n2.getLight(bank, nodemgr) > undiminish_light(oldlight))
530                                 {
531                                         lighted_nodes.insert(n2pos);
532                                         changed = true;
533                                 }
534                                 /*
535                                         If the neighbor is dimmer than how much light this node
536                                         would spread on it, add to list
537                                 */
538                                 if(n2.getLight(bank, nodemgr) < newlight)
539                                 {
540                                         if(nodemgr->get(n2).light_propagates)
541                                         {
542                                                 n2.setLight(bank, newlight, nodemgr);
543                                                 block->setNode(relpos, n2);
544                                                 lighted_nodes.insert(n2pos);
545                                                 changed = true;
546                                         }
547                                 }
548
549                                 // Add to modified_blocks
550                                 if(changed == true && block_checked_in_modified == false)
551                                 {
552                                         // If the block is not found in modified_blocks, add.
553                                         if(modified_blocks.find(blockpos) == modified_blocks.end())
554                                         {
555                                                 modified_blocks[blockpos] = block;
556                                         }
557                                         block_checked_in_modified = true;
558                                 }
559                         }
560                         catch(InvalidPositionException &e)
561                         {
562                                 continue;
563                         }
564                 }
565         }
566
567         /*infostream<<"spreadLight(): Changed block "
568                         <<blockchangecount<<" times"
569                         <<" for "<<from_nodes.size()<<" nodes"
570                         <<std::endl;*/
571
572         if(lighted_nodes.size() > 0)
573                 spreadLight(bank, lighted_nodes, modified_blocks);
574 }
575
576 /*
577         A single-node source variation of the above.
578 */
579 void Map::lightNeighbors(enum LightBank bank,
580                 v3s16 pos,
581                 std::map<v3s16, MapBlock*> & modified_blocks)
582 {
583         std::set<v3s16> from_nodes;
584         from_nodes.insert(pos);
585         spreadLight(bank, from_nodes, modified_blocks);
586 }
587
588 v3s16 Map::getBrightestNeighbour(enum LightBank bank, v3s16 p)
589 {
590         INodeDefManager *nodemgr = m_gamedef->ndef();
591
592         v3s16 dirs[6] = {
593                 v3s16(0,0,1), // back
594                 v3s16(0,1,0), // top
595                 v3s16(1,0,0), // right
596                 v3s16(0,0,-1), // front
597                 v3s16(0,-1,0), // bottom
598                 v3s16(-1,0,0), // left
599         };
600
601         u8 brightest_light = 0;
602         v3s16 brightest_pos(0,0,0);
603         bool found_something = false;
604
605         // Loop through 6 neighbors
606         for(u16 i=0; i<6; i++){
607                 // Get the position of the neighbor node
608                 v3s16 n2pos = p + dirs[i];
609                 MapNode n2;
610                 try{
611                         n2 = getNode(n2pos);
612                 }
613                 catch(InvalidPositionException &e)
614                 {
615                         continue;
616                 }
617                 if(n2.getLight(bank, nodemgr) > brightest_light || found_something == false){
618                         brightest_light = n2.getLight(bank, nodemgr);
619                         brightest_pos = n2pos;
620                         found_something = true;
621                 }
622         }
623
624         if(found_something == false)
625                 throw InvalidPositionException();
626
627         return brightest_pos;
628 }
629
630 /*
631         Propagates sunlight down from a node.
632         Starting point gets sunlight.
633
634         Returns the lowest y value of where the sunlight went.
635
636         Mud is turned into grass in where the sunlight stops.
637 */
638 s16 Map::propagateSunlight(v3s16 start,
639                 std::map<v3s16, MapBlock*> & modified_blocks)
640 {
641         INodeDefManager *nodemgr = m_gamedef->ndef();
642
643         s16 y = start.Y;
644         for(; ; y--)
645         {
646                 v3s16 pos(start.X, y, start.Z);
647
648                 v3s16 blockpos = getNodeBlockPos(pos);
649                 MapBlock *block;
650                 try{
651                         block = getBlockNoCreate(blockpos);
652                 }
653                 catch(InvalidPositionException &e)
654                 {
655                         break;
656                 }
657
658                 v3s16 relpos = pos - blockpos*MAP_BLOCKSIZE;
659                 MapNode n = block->getNode(relpos);
660
661                 if(nodemgr->get(n).sunlight_propagates)
662                 {
663                         n.setLight(LIGHTBANK_DAY, LIGHT_SUN, nodemgr);
664                         block->setNode(relpos, n);
665
666                         modified_blocks[blockpos] = block;
667                 }
668                 else
669                 {
670                         // Sunlight goes no further
671                         break;
672                 }
673         }
674         return y + 1;
675 }
676
677 void Map::updateLighting(enum LightBank bank,
678                 std::map<v3s16, MapBlock*> & a_blocks,
679                 std::map<v3s16, MapBlock*> & modified_blocks)
680 {
681         INodeDefManager *nodemgr = m_gamedef->ndef();
682
683         /*m_dout<<DTIME<<"Map::updateLighting(): "
684                         <<a_blocks.size()<<" blocks."<<std::endl;*/
685
686         //TimeTaker timer("updateLighting");
687
688         // For debugging
689         //bool debug=true;
690         //u32 count_was = modified_blocks.size();
691
692         std::map<v3s16, MapBlock*> blocks_to_update;
693
694         std::set<v3s16> light_sources;
695
696         std::map<v3s16, u8> unlight_from;
697
698         int num_bottom_invalid = 0;
699
700         {
701         //TimeTaker t("first stuff");
702
703         for(std::map<v3s16, MapBlock*>::iterator i = a_blocks.begin();
704                 i != a_blocks.end(); ++i)
705         {
706                 MapBlock *block = i->second;
707
708                 for(;;)
709                 {
710                         // Don't bother with dummy blocks.
711                         if(block->isDummy())
712                                 break;
713
714                         v3s16 pos = block->getPos();
715                         v3s16 posnodes = block->getPosRelative();
716                         modified_blocks[pos] = block;
717                         blocks_to_update[pos] = block;
718
719                         /*
720                                 Clear all light from block
721                         */
722                         for(s16 z=0; z<MAP_BLOCKSIZE; z++)
723                         for(s16 x=0; x<MAP_BLOCKSIZE; x++)
724                         for(s16 y=0; y<MAP_BLOCKSIZE; y++)
725                         {
726
727                                 try{
728                                         v3s16 p(x,y,z);
729                                         MapNode n = block->getNode(p);
730                                         u8 oldlight = n.getLight(bank, nodemgr);
731                                         n.setLight(bank, 0, nodemgr);
732                                         block->setNode(p, n);
733
734                                         // If node sources light, add to list
735                                         u8 source = nodemgr->get(n).light_source;
736                                         if(source != 0)
737                                                 light_sources.insert(p + posnodes);
738
739                                         // Collect borders for unlighting
740                                         if((x==0 || x == MAP_BLOCKSIZE-1
741                                         || y==0 || y == MAP_BLOCKSIZE-1
742                                         || z==0 || z == MAP_BLOCKSIZE-1)
743                                         && oldlight != 0)
744                                         {
745                                                 v3s16 p_map = p + posnodes;
746                                                 unlight_from[p_map] = oldlight;
747                                         }
748                                 }
749                                 catch(InvalidPositionException &e)
750                                 {
751                                         /*
752                                                 This would happen when dealing with a
753                                                 dummy block.
754                                         */
755                                         //assert(0);
756                                         infostream<<"updateLighting(): InvalidPositionException"
757                                                         <<std::endl;
758                                 }
759                         }
760
761                         if(bank == LIGHTBANK_DAY)
762                         {
763                                 bool bottom_valid = block->propagateSunlight(light_sources);
764
765                                 if(!bottom_valid)
766                                         num_bottom_invalid++;
767
768                                 // If bottom is valid, we're done.
769                                 if(bottom_valid)
770                                         break;
771                         }
772                         else if(bank == LIGHTBANK_NIGHT)
773                         {
774                                 // For night lighting, sunlight is not propagated
775                                 break;
776                         }
777                         else
778                         {
779                                 // Invalid lighting bank
780                                 assert(0);
781                         }
782
783                         /*infostream<<"Bottom for sunlight-propagated block ("
784                                         <<pos.X<<","<<pos.Y<<","<<pos.Z<<") not valid"
785                                         <<std::endl;*/
786
787                         // Bottom sunlight is not valid; get the block and loop to it
788
789                         pos.Y--;
790                         try{
791                                 block = getBlockNoCreate(pos);
792                         }
793                         catch(InvalidPositionException &e)
794                         {
795                                 assert(0);
796                         }
797
798                 }
799         }
800
801         }
802
803         /*
804                 Enable this to disable proper lighting for speeding up map
805                 generation for testing or whatever
806         */
807 #if 0
808         //if(g_settings->get(""))
809         {
810                 core::map<v3s16, MapBlock*>::Iterator i;
811                 i = blocks_to_update.getIterator();
812                 for(; i.atEnd() == false; i++)
813                 {
814                         MapBlock *block = i.getNode()->getValue();
815                         v3s16 p = block->getPos();
816                         block->setLightingExpired(false);
817                 }
818                 return;
819         }
820 #endif
821
822 #if 1
823         {
824                 //TimeTaker timer("unspreadLight");
825                 unspreadLight(bank, unlight_from, light_sources, modified_blocks);
826         }
827
828         /*if(debug)
829         {
830                 u32 diff = modified_blocks.size() - count_was;
831                 count_was = modified_blocks.size();
832                 infostream<<"unspreadLight modified "<<diff<<std::endl;
833         }*/
834
835         {
836                 //TimeTaker timer("spreadLight");
837                 spreadLight(bank, light_sources, modified_blocks);
838         }
839
840         /*if(debug)
841         {
842                 u32 diff = modified_blocks.size() - count_was;
843                 count_was = modified_blocks.size();
844                 infostream<<"spreadLight modified "<<diff<<std::endl;
845         }*/
846 #endif
847
848 #if 0
849         {
850                 //MapVoxelManipulator vmanip(this);
851
852                 // Make a manual voxel manipulator and load all the blocks
853                 // that touch the requested blocks
854                 ManualMapVoxelManipulator vmanip(this);
855
856                 {
857                 //TimeTaker timer("initialEmerge");
858
859                 core::map<v3s16, MapBlock*>::Iterator i;
860                 i = blocks_to_update.getIterator();
861                 for(; i.atEnd() == false; i++)
862                 {
863                         MapBlock *block = i.getNode()->getValue();
864                         v3s16 p = block->getPos();
865
866                         // Add all surrounding blocks
867                         vmanip.initialEmerge(p - v3s16(1,1,1), p + v3s16(1,1,1));
868
869                         /*
870                                 Add all surrounding blocks that have up-to-date lighting
871                                 NOTE: This doesn't quite do the job (not everything
872                                           appropriate is lighted)
873                         */
874                         /*for(s16 z=-1; z<=1; z++)
875                         for(s16 y=-1; y<=1; y++)
876                         for(s16 x=-1; x<=1; x++)
877                         {
878                                 v3s16 p2 = p + v3s16(x,y,z);
879                                 MapBlock *block = getBlockNoCreateNoEx(p2);
880                                 if(block == NULL)
881                                         continue;
882                                 if(block->isDummy())
883                                         continue;
884                                 if(block->getLightingExpired())
885                                         continue;
886                                 vmanip.initialEmerge(p2, p2);
887                         }*/
888
889                         // Lighting of block will be updated completely
890                         block->setLightingExpired(false);
891                 }
892                 }
893
894                 {
895                         //TimeTaker timer("unSpreadLight");
896                         vmanip.unspreadLight(bank, unlight_from, light_sources, nodemgr);
897                 }
898                 {
899                         //TimeTaker timer("spreadLight");
900                         vmanip.spreadLight(bank, light_sources, nodemgr);
901                 }
902                 {
903                         //TimeTaker timer("blitBack");
904                         vmanip.blitBack(modified_blocks);
905                 }
906                 /*infostream<<"emerge_time="<<emerge_time<<std::endl;
907                 emerge_time = 0;*/
908         }
909 #endif
910
911         //m_dout<<"Done ("<<getTimestamp()<<")"<<std::endl;
912 }
913
914 void Map::updateLighting(std::map<v3s16, MapBlock*> & a_blocks,
915                 std::map<v3s16, MapBlock*> & modified_blocks)
916 {
917         updateLighting(LIGHTBANK_DAY, a_blocks, modified_blocks);
918         updateLighting(LIGHTBANK_NIGHT, a_blocks, modified_blocks);
919
920         /*
921                 Update information about whether day and night light differ
922         */
923         for(std::map<v3s16, MapBlock*>::iterator
924                         i = modified_blocks.begin();
925                         i != modified_blocks.end(); ++i)
926         {
927                 MapBlock *block = i->second;
928                 block->expireDayNightDiff();
929         }
930 }
931
932 /*
933 */
934 void Map::addNodeAndUpdate(v3s16 p, MapNode n,
935                 std::map<v3s16, MapBlock*> &modified_blocks,
936                 bool remove_metadata)
937 {
938         INodeDefManager *ndef = m_gamedef->ndef();
939
940         /*PrintInfo(m_dout);
941         m_dout<<DTIME<<"Map::addNodeAndUpdate(): p=("
942                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
943
944         /*
945                 From this node to nodes underneath:
946                 If lighting is sunlight (1.0), unlight neighbours and
947                 set lighting to 0.
948                 Else discontinue.
949         */
950
951         v3s16 toppos = p + v3s16(0,1,0);
952         //v3s16 bottompos = p + v3s16(0,-1,0);
953
954         bool node_under_sunlight = true;
955         std::set<v3s16> light_sources;
956
957         /*
958                 Collect old node for rollback
959         */
960         RollbackNode rollback_oldnode(this, p, m_gamedef);
961
962         /*
963                 If there is a node at top and it doesn't have sunlight,
964                 there has not been any sunlight going down.
965
966                 Otherwise there probably is.
967         */
968         try{
969                 MapNode topnode = getNode(toppos);
970
971                 if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
972                         node_under_sunlight = false;
973         }
974         catch(InvalidPositionException &e)
975         {
976         }
977
978         /*
979                 Remove all light that has come out of this node
980         */
981
982         enum LightBank banks[] =
983         {
984                 LIGHTBANK_DAY,
985                 LIGHTBANK_NIGHT
986         };
987         for(s32 i=0; i<2; i++)
988         {
989                 enum LightBank bank = banks[i];
990
991                 u8 lightwas = getNode(p).getLight(bank, ndef);
992
993                 // Add the block of the added node to modified_blocks
994                 v3s16 blockpos = getNodeBlockPos(p);
995                 MapBlock * block = getBlockNoCreate(blockpos);
996                 assert(block != NULL);
997                 modified_blocks[blockpos] = block;
998
999                 assert(isValidPosition(p));
1000
1001                 // Unlight neighbours of node.
1002                 // This means setting light of all consequent dimmer nodes
1003                 // to 0.
1004                 // This also collects the nodes at the border which will spread
1005                 // light again into this.
1006                 unLightNeighbors(bank, p, lightwas, light_sources, modified_blocks);
1007
1008                 n.setLight(bank, 0, ndef);
1009         }
1010
1011         /*
1012                 If node lets sunlight through and is under sunlight, it has
1013                 sunlight too.
1014         */
1015         if(node_under_sunlight && ndef->get(n).sunlight_propagates)
1016         {
1017                 n.setLight(LIGHTBANK_DAY, LIGHT_SUN, ndef);
1018         }
1019
1020         /*
1021                 Remove node metadata
1022         */
1023         if (remove_metadata) {
1024                 removeNodeMetadata(p);
1025         }
1026
1027         /*
1028                 Set the node on the map
1029         */
1030
1031         setNode(p, n);
1032
1033         /*
1034                 If node is under sunlight and doesn't let sunlight through,
1035                 take all sunlighted nodes under it and clear light from them
1036                 and from where the light has been spread.
1037                 TODO: This could be optimized by mass-unlighting instead
1038                           of looping
1039         */
1040         if(node_under_sunlight && !ndef->get(n).sunlight_propagates)
1041         {
1042                 s16 y = p.Y - 1;
1043                 for(;; y--){
1044                         //m_dout<<DTIME<<"y="<<y<<std::endl;
1045                         v3s16 n2pos(p.X, y, p.Z);
1046
1047                         MapNode n2;
1048                         try{
1049                                 n2 = getNode(n2pos);
1050                         }
1051                         catch(InvalidPositionException &e)
1052                         {
1053                                 break;
1054                         }
1055
1056                         if(n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN)
1057                         {
1058                                 unLightNeighbors(LIGHTBANK_DAY,
1059                                                 n2pos, n2.getLight(LIGHTBANK_DAY, ndef),
1060                                                 light_sources, modified_blocks);
1061                                 n2.setLight(LIGHTBANK_DAY, 0, ndef);
1062                                 setNode(n2pos, n2);
1063                         }
1064                         else
1065                                 break;
1066                 }
1067         }
1068
1069         for(s32 i=0; i<2; i++)
1070         {
1071                 enum LightBank bank = banks[i];
1072
1073                 /*
1074                         Spread light from all nodes that might be capable of doing so
1075                 */
1076                 spreadLight(bank, light_sources, modified_blocks);
1077         }
1078
1079         /*
1080                 Update information about whether day and night light differ
1081         */
1082         for(std::map<v3s16, MapBlock*>::iterator
1083                         i = modified_blocks.begin();
1084                         i != modified_blocks.end(); ++i)
1085         {
1086                 i->second->expireDayNightDiff();
1087         }
1088
1089         /*
1090                 Report for rollback
1091         */
1092         if(m_gamedef->rollback())
1093         {
1094                 RollbackNode rollback_newnode(this, p, m_gamedef);
1095                 RollbackAction action;
1096                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
1097                 m_gamedef->rollback()->reportAction(action);
1098         }
1099
1100         /*
1101                 Add neighboring liquid nodes and the node itself if it is
1102                 liquid (=water node was added) to transform queue.
1103         */
1104         v3s16 dirs[7] = {
1105                 v3s16(0,0,0), // self
1106                 v3s16(0,0,1), // back
1107                 v3s16(0,1,0), // top
1108                 v3s16(1,0,0), // right
1109                 v3s16(0,0,-1), // front
1110                 v3s16(0,-1,0), // bottom
1111                 v3s16(-1,0,0), // left
1112         };
1113         for(u16 i=0; i<7; i++)
1114         {
1115                 try
1116                 {
1117
1118                 v3s16 p2 = p + dirs[i];
1119
1120                 MapNode n2 = getNode(p2);
1121                 if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
1122                 {
1123                         m_transforming_liquid.push_back(p2);
1124                 }
1125
1126                 }catch(InvalidPositionException &e)
1127                 {
1128                 }
1129         }
1130 }
1131
1132 /*
1133 */
1134 void Map::removeNodeAndUpdate(v3s16 p,
1135                 std::map<v3s16, MapBlock*> &modified_blocks)
1136 {
1137         INodeDefManager *ndef = m_gamedef->ndef();
1138
1139         /*PrintInfo(m_dout);
1140         m_dout<<DTIME<<"Map::removeNodeAndUpdate(): p=("
1141                         <<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
1142
1143         bool node_under_sunlight = true;
1144
1145         v3s16 toppos = p + v3s16(0,1,0);
1146
1147         // Node will be replaced with this
1148         content_t replace_material = CONTENT_AIR;
1149
1150         /*
1151                 Collect old node for rollback
1152         */
1153         RollbackNode rollback_oldnode(this, p, m_gamedef);
1154
1155         /*
1156                 If there is a node at top and it doesn't have sunlight,
1157                 there will be no sunlight going down.
1158         */
1159         try{
1160                 MapNode topnode = getNode(toppos);
1161
1162                 if(topnode.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN)
1163                         node_under_sunlight = false;
1164         }
1165         catch(InvalidPositionException &e)
1166         {
1167         }
1168
1169         std::set<v3s16> light_sources;
1170
1171         enum LightBank banks[] =
1172         {
1173                 LIGHTBANK_DAY,
1174                 LIGHTBANK_NIGHT
1175         };
1176         for(s32 i=0; i<2; i++)
1177         {
1178                 enum LightBank bank = banks[i];
1179
1180                 /*
1181                         Unlight neighbors (in case the node is a light source)
1182                 */
1183                 unLightNeighbors(bank, p,
1184                                 getNode(p).getLight(bank, ndef),
1185                                 light_sources, modified_blocks);
1186         }
1187
1188         /*
1189                 Remove node metadata
1190         */
1191
1192         removeNodeMetadata(p);
1193
1194         /*
1195                 Remove the node.
1196                 This also clears the lighting.
1197         */
1198
1199         MapNode n;
1200         n.setContent(replace_material);
1201         setNode(p, n);
1202
1203         for(s32 i=0; i<2; i++)
1204         {
1205                 enum LightBank bank = banks[i];
1206
1207                 /*
1208                         Recalculate lighting
1209                 */
1210                 spreadLight(bank, light_sources, modified_blocks);
1211         }
1212
1213         // Add the block of the removed node to modified_blocks
1214         v3s16 blockpos = getNodeBlockPos(p);
1215         MapBlock * block = getBlockNoCreate(blockpos);
1216         assert(block != NULL);
1217         modified_blocks[blockpos] = block;
1218
1219         /*
1220                 If the removed node was under sunlight, propagate the
1221                 sunlight down from it and then light all neighbors
1222                 of the propagated blocks.
1223         */
1224         if(node_under_sunlight)
1225         {
1226                 s16 ybottom = propagateSunlight(p, modified_blocks);
1227                 /*m_dout<<DTIME<<"Node was under sunlight. "
1228                                 "Propagating sunlight";
1229                 m_dout<<DTIME<<" -> ybottom="<<ybottom<<std::endl;*/
1230                 s16 y = p.Y;
1231                 for(; y >= ybottom; y--)
1232                 {
1233                         v3s16 p2(p.X, y, p.Z);
1234                         /*m_dout<<DTIME<<"lighting neighbors of node ("
1235                                         <<p2.X<<","<<p2.Y<<","<<p2.Z<<")"
1236                                         <<std::endl;*/
1237                         lightNeighbors(LIGHTBANK_DAY, p2, modified_blocks);
1238                 }
1239         }
1240         else
1241         {
1242                 // Set the lighting of this node to 0
1243                 // TODO: Is this needed? Lighting is cleared up there already.
1244                 try{
1245                         MapNode n = getNode(p);
1246                         n.setLight(LIGHTBANK_DAY, 0, ndef);
1247                         setNode(p, n);
1248                 }
1249                 catch(InvalidPositionException &e)
1250                 {
1251                         assert(0);
1252                 }
1253         }
1254
1255         for(s32 i=0; i<2; i++)
1256         {
1257                 enum LightBank bank = banks[i];
1258
1259                 // Get the brightest neighbour node and propagate light from it
1260                 v3s16 n2p = getBrightestNeighbour(bank, p);
1261                 try{
1262                         //MapNode n2 = getNode(n2p);
1263                         lightNeighbors(bank, n2p, modified_blocks);
1264                 }
1265                 catch(InvalidPositionException &e)
1266                 {
1267                 }
1268         }
1269
1270         /*
1271                 Update information about whether day and night light differ
1272         */
1273         for(std::map<v3s16, MapBlock*>::iterator
1274                         i = modified_blocks.begin();
1275                         i != modified_blocks.end(); ++i)
1276         {
1277                 i->second->expireDayNightDiff();
1278         }
1279
1280         /*
1281                 Report for rollback
1282         */
1283         if(m_gamedef->rollback())
1284         {
1285                 RollbackNode rollback_newnode(this, p, m_gamedef);
1286                 RollbackAction action;
1287                 action.setSetNode(p, rollback_oldnode, rollback_newnode);
1288                 m_gamedef->rollback()->reportAction(action);
1289         }
1290
1291         /*
1292                 Add neighboring liquid nodes and this node to transform queue.
1293                 (it's vital for the node itself to get updated last.)
1294         */
1295         v3s16 dirs[7] = {
1296                 v3s16(0,0,1), // back
1297                 v3s16(0,1,0), // top
1298                 v3s16(1,0,0), // right
1299                 v3s16(0,0,-1), // front
1300                 v3s16(0,-1,0), // bottom
1301                 v3s16(-1,0,0), // left
1302                 v3s16(0,0,0), // self
1303         };
1304         for(u16 i=0; i<7; i++)
1305         {
1306                 try
1307                 {
1308
1309                 v3s16 p2 = p + dirs[i];
1310
1311                 MapNode n2 = getNode(p2);
1312                 if(ndef->get(n2).isLiquid() || n2.getContent() == CONTENT_AIR)
1313                 {
1314                         m_transforming_liquid.push_back(p2);
1315                 }
1316
1317                 }catch(InvalidPositionException &e)
1318                 {
1319                 }
1320         }
1321 }
1322
1323 bool Map::addNodeWithEvent(v3s16 p, MapNode n, bool remove_metadata)
1324 {
1325         MapEditEvent event;
1326         event.type = remove_metadata ? MEET_ADDNODE : MEET_SWAPNODE;
1327         event.p = p;
1328         event.n = n;
1329
1330         bool succeeded = true;
1331         try{
1332                 std::map<v3s16, MapBlock*> modified_blocks;
1333                 addNodeAndUpdate(p, n, modified_blocks, remove_metadata);
1334
1335                 // Copy modified_blocks to event
1336                 for(std::map<v3s16, MapBlock*>::iterator
1337                                 i = modified_blocks.begin();
1338                                 i != modified_blocks.end(); ++i)
1339                 {
1340                         event.modified_blocks.insert(i->first);
1341                 }
1342         }
1343         catch(InvalidPositionException &e){
1344                 succeeded = false;
1345         }
1346
1347         dispatchEvent(&event);
1348
1349         return succeeded;
1350 }
1351
1352 bool Map::removeNodeWithEvent(v3s16 p)
1353 {
1354         MapEditEvent event;
1355         event.type = MEET_REMOVENODE;
1356         event.p = p;
1357
1358         bool succeeded = true;
1359         try{
1360                 std::map<v3s16, MapBlock*> modified_blocks;
1361                 removeNodeAndUpdate(p, modified_blocks);
1362
1363                 // Copy modified_blocks to event
1364                 for(std::map<v3s16, MapBlock*>::iterator
1365                                 i = modified_blocks.begin();
1366                                 i != modified_blocks.end(); ++i)
1367                 {
1368                         event.modified_blocks.insert(i->first);
1369                 }
1370         }
1371         catch(InvalidPositionException &e){
1372                 succeeded = false;
1373         }
1374
1375         dispatchEvent(&event);
1376
1377         return succeeded;
1378 }
1379
1380 bool Map::getDayNightDiff(v3s16 blockpos)
1381 {
1382         try{
1383                 v3s16 p = blockpos + v3s16(0,0,0);
1384                 MapBlock *b = getBlockNoCreate(p);
1385                 if(b->getDayNightDiff())
1386                         return true;
1387         }
1388         catch(InvalidPositionException &e){}
1389         // Leading edges
1390         try{
1391                 v3s16 p = blockpos + v3s16(-1,0,0);
1392                 MapBlock *b = getBlockNoCreate(p);
1393                 if(b->getDayNightDiff())
1394                         return true;
1395         }
1396         catch(InvalidPositionException &e){}
1397         try{
1398                 v3s16 p = blockpos + v3s16(0,-1,0);
1399                 MapBlock *b = getBlockNoCreate(p);
1400                 if(b->getDayNightDiff())
1401                         return true;
1402         }
1403         catch(InvalidPositionException &e){}
1404         try{
1405                 v3s16 p = blockpos + v3s16(0,0,-1);
1406                 MapBlock *b = getBlockNoCreate(p);
1407                 if(b->getDayNightDiff())
1408                         return true;
1409         }
1410         catch(InvalidPositionException &e){}
1411         // Trailing edges
1412         try{
1413                 v3s16 p = blockpos + v3s16(1,0,0);
1414                 MapBlock *b = getBlockNoCreate(p);
1415                 if(b->getDayNightDiff())
1416                         return true;
1417         }
1418         catch(InvalidPositionException &e){}
1419         try{
1420                 v3s16 p = blockpos + v3s16(0,1,0);
1421                 MapBlock *b = getBlockNoCreate(p);
1422                 if(b->getDayNightDiff())
1423                         return true;
1424         }
1425         catch(InvalidPositionException &e){}
1426         try{
1427                 v3s16 p = blockpos + v3s16(0,0,1);
1428                 MapBlock *b = getBlockNoCreate(p);
1429                 if(b->getDayNightDiff())
1430                         return true;
1431         }
1432         catch(InvalidPositionException &e){}
1433
1434         return false;
1435 }
1436
1437 /*
1438         Updates usage timers
1439 */
1440 void Map::timerUpdate(float dtime, float unload_timeout,
1441                 std::list<v3s16> *unloaded_blocks)
1442 {
1443         bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
1444
1445         // Profile modified reasons
1446         Profiler modprofiler;
1447
1448         std::list<v2s16> sector_deletion_queue;
1449         u32 deleted_blocks_count = 0;
1450         u32 saved_blocks_count = 0;
1451         u32 block_count_all = 0;
1452
1453         beginSave();
1454         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
1455                 si != m_sectors.end(); ++si)
1456         {
1457                 MapSector *sector = si->second;
1458
1459                 bool all_blocks_deleted = true;
1460
1461                 std::list<MapBlock*> blocks;
1462                 sector->getBlocks(blocks);
1463
1464                 for(std::list<MapBlock*>::iterator i = blocks.begin();
1465                                 i != blocks.end(); ++i)
1466                 {
1467                         MapBlock *block = (*i);
1468
1469                         block->incrementUsageTimer(dtime);
1470
1471                         if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout)
1472                         {
1473                                 v3s16 p = block->getPos();
1474
1475                                 // Save if modified
1476                                 if(block->getModified() != MOD_STATE_CLEAN
1477                                                 && save_before_unloading)
1478                                 {
1479                                         modprofiler.add(block->getModifiedReason(), 1);
1480                                         saveBlock(block);
1481                                         saved_blocks_count++;
1482                                 }
1483
1484                                 // Delete from memory
1485                                 sector->deleteBlock(block);
1486
1487                                 if(unloaded_blocks)
1488                                         unloaded_blocks->push_back(p);
1489
1490                                 deleted_blocks_count++;
1491                         }
1492                         else
1493                         {
1494                                 all_blocks_deleted = false;
1495                                 block_count_all++;
1496                         }
1497                 }
1498
1499                 if(all_blocks_deleted)
1500                 {
1501                         sector_deletion_queue.push_back(si->first);
1502                 }
1503         }
1504         endSave();
1505
1506         // Finally delete the empty sectors
1507         deleteSectors(sector_deletion_queue);
1508
1509         if(deleted_blocks_count != 0)
1510         {
1511                 PrintInfo(infostream); // ServerMap/ClientMap:
1512                 infostream<<"Unloaded "<<deleted_blocks_count
1513                                 <<" blocks from memory";
1514                 if(save_before_unloading)
1515                         infostream<<", of which "<<saved_blocks_count<<" were written";
1516                 infostream<<", "<<block_count_all<<" blocks in memory";
1517                 infostream<<"."<<std::endl;
1518                 if(saved_blocks_count != 0){
1519                         PrintInfo(infostream); // ServerMap/ClientMap:
1520                         infostream<<"Blocks modified by: "<<std::endl;
1521                         modprofiler.print(infostream);
1522                 }
1523         }
1524 }
1525
1526 void Map::unloadUnreferencedBlocks(std::list<v3s16> *unloaded_blocks)
1527 {
1528         timerUpdate(0.0, -1.0, unloaded_blocks);
1529 }
1530
1531 void Map::deleteSectors(std::list<v2s16> &list)
1532 {
1533         for(std::list<v2s16>::iterator j = list.begin();
1534                 j != list.end(); ++j)
1535         {
1536                 MapSector *sector = m_sectors[*j];
1537                 // If sector is in sector cache, remove it from there
1538                 if(m_sector_cache == sector)
1539                         m_sector_cache = NULL;
1540                 // Remove from map and delete
1541                 m_sectors.erase(*j);
1542                 delete sector;
1543         }
1544 }
1545
1546 #if 0
1547 void Map::unloadUnusedData(float timeout,
1548                 core::list<v3s16> *deleted_blocks)
1549 {
1550         core::list<v2s16> sector_deletion_queue;
1551         u32 deleted_blocks_count = 0;
1552         u32 saved_blocks_count = 0;
1553
1554         core::map<v2s16, MapSector*>::Iterator si = m_sectors.getIterator();
1555         for(; si.atEnd() == false; si++)
1556         {
1557                 MapSector *sector = si.getNode()->getValue();
1558
1559                 bool all_blocks_deleted = true;
1560
1561                 core::list<MapBlock*> blocks;
1562                 sector->getBlocks(blocks);
1563                 for(core::list<MapBlock*>::Iterator i = blocks.begin();
1564                                 i != blocks.end(); i++)
1565                 {
1566                         MapBlock *block = (*i);
1567
1568                         if(block->getUsageTimer() > timeout)
1569                         {
1570                                 // Save if modified
1571                                 if(block->getModified() != MOD_STATE_CLEAN)
1572                                 {
1573                                         saveBlock(block);
1574                                         saved_blocks_count++;
1575                                 }
1576                                 // Delete from memory
1577                                 sector->deleteBlock(block);
1578                                 deleted_blocks_count++;
1579                         }
1580                         else
1581                         {
1582                                 all_blocks_deleted = false;
1583                         }
1584                 }
1585
1586                 if(all_blocks_deleted)
1587                 {
1588                         sector_deletion_queue.push_back(si.getNode()->getKey());
1589                 }
1590         }
1591
1592         deleteSectors(sector_deletion_queue);
1593
1594         infostream<<"Map: Unloaded "<<deleted_blocks_count<<" blocks from memory"
1595                         <<", of which "<<saved_blocks_count<<" were wr."
1596                         <<std::endl;
1597
1598         //return sector_deletion_queue.getSize();
1599         //return deleted_blocks_count;
1600 }
1601 #endif
1602
1603 void Map::PrintInfo(std::ostream &out)
1604 {
1605         out<<"Map: ";
1606 }
1607
1608 #define WATER_DROP_BOOST 4
1609
1610 enum NeighborType {
1611         NEIGHBOR_UPPER,
1612         NEIGHBOR_SAME_LEVEL,
1613         NEIGHBOR_LOWER
1614 };
1615 struct NodeNeighbor {
1616         MapNode n;
1617         NeighborType t;
1618         v3s16 p;
1619         bool l; //can liquid
1620 };
1621
1622 void Map::transforming_liquid_add(v3s16 p) {
1623         m_transforming_liquid.push_back(p);
1624 }
1625
1626 s32 Map::transforming_liquid_size() {
1627         return m_transforming_liquid.size();
1628 }
1629
1630 void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
1631 {
1632         INodeDefManager *nodemgr = m_gamedef->ndef();
1633
1634         DSTACK(__FUNCTION_NAME);
1635         //TimeTaker timer("transformLiquids()");
1636
1637         u32 loopcount = 0;
1638         u32 initial_size = m_transforming_liquid.size();
1639
1640         /*if(initial_size != 0)
1641                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1642
1643         // list of nodes that due to viscosity have not reached their max level height
1644         UniqueQueue<v3s16> must_reflow;
1645
1646         // List of MapBlocks that will require a lighting update (due to lava)
1647         std::map<v3s16, MapBlock*> lighting_modified_blocks;
1648
1649         u16 loop_max = g_settings->getU16("liquid_loop_max");
1650
1651         while(m_transforming_liquid.size() != 0)
1652         {
1653                 // This should be done here so that it is done when continue is used
1654                 if(loopcount >= initial_size || loopcount >= loop_max)
1655                         break;
1656                 loopcount++;
1657
1658                 /*
1659                         Get a queued transforming liquid node
1660                 */
1661                 v3s16 p0 = m_transforming_liquid.pop_front();
1662
1663                 MapNode n0 = getNodeNoEx(p0);
1664
1665                 /*
1666                         Collect information about current node
1667                  */
1668                 s8 liquid_level = -1;
1669                 content_t liquid_kind = CONTENT_IGNORE;
1670                 LiquidType liquid_type = nodemgr->get(n0).liquid_type;
1671                 switch (liquid_type) {
1672                         case LIQUID_SOURCE:
1673                                 liquid_level = LIQUID_LEVEL_SOURCE;
1674                                 liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
1675                                 break;
1676                         case LIQUID_FLOWING:
1677                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1678                                 liquid_kind = n0.getContent();
1679                                 break;
1680                         case LIQUID_NONE:
1681                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1682                                 // continue with the next node.
1683                                 if (n0.getContent() != CONTENT_AIR)
1684                                         continue;
1685                                 liquid_kind = CONTENT_AIR;
1686                                 break;
1687                 }
1688
1689                 /*
1690                         Collect information about the environment
1691                  */
1692                 const v3s16 *dirs = g_6dirs;
1693                 NodeNeighbor sources[6]; // surrounding sources
1694                 int num_sources = 0;
1695                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1696                 int num_flows = 0;
1697                 NodeNeighbor airs[6]; // surrounding air
1698                 int num_airs = 0;
1699                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1700                 int num_neutrals = 0;
1701                 bool flowing_down = false;
1702                 for (u16 i = 0; i < 6; i++) {
1703                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1704                         switch (i) {
1705                                 case 1:
1706                                         nt = NEIGHBOR_UPPER;
1707                                         break;
1708                                 case 4:
1709                                         nt = NEIGHBOR_LOWER;
1710                                         break;
1711                         }
1712                         v3s16 npos = p0 + dirs[i];
1713                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
1714                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1715                                 case LIQUID_NONE:
1716                                         if (nb.n.getContent() == CONTENT_AIR) {
1717                                                 airs[num_airs++] = nb;
1718                                                 // if the current node is a water source the neighbor
1719                                                 // should be enqueded for transformation regardless of whether the
1720                                                 // current node changes or not.
1721                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1722                                                         m_transforming_liquid.push_back(npos);
1723                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1724                                                 if (nb.t == NEIGHBOR_LOWER) {
1725                                                         flowing_down = true;
1726                                                 }
1727                                         } else {
1728                                                 neutrals[num_neutrals++] = nb;
1729                                         }
1730                                         break;
1731                                 case LIQUID_SOURCE:
1732                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1733                                         if (liquid_kind == CONTENT_AIR)
1734                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1735                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1736                                                 neutrals[num_neutrals++] = nb;
1737                                         } else {
1738                                                 // Do not count bottom source, it will screw things up
1739                                                 if(dirs[i].Y != -1)
1740                                                         sources[num_sources++] = nb;
1741                                         }
1742                                         break;
1743                                 case LIQUID_FLOWING:
1744                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1745                                         if (liquid_kind == CONTENT_AIR)
1746                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1747                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1748                                                 neutrals[num_neutrals++] = nb;
1749                                         } else {
1750                                                 flows[num_flows++] = nb;
1751                                                 if (nb.t == NEIGHBOR_LOWER)
1752                                                         flowing_down = true;
1753                                         }
1754                                         break;
1755                         }
1756                 }
1757
1758                 /*
1759                         decide on the type (and possibly level) of the current node
1760                  */
1761                 content_t new_node_content;
1762                 s8 new_node_level = -1;
1763                 s8 max_node_level = -1;
1764                 u8 range = rangelim(nodemgr->get(liquid_kind).liquid_range, 0, LIQUID_LEVEL_MAX+1);
1765                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
1766                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1767                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1768                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1769                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1770                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
1771                         // liquid_kind is set properly, see above
1772                         new_node_content = liquid_kind;
1773                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1774                         if (new_node_level < (LIQUID_LEVEL_MAX+1-range))
1775                                 new_node_content = CONTENT_AIR;
1776                 } else {
1777                         // no surrounding sources, so get the maximum level that can flow into this node
1778                         for (u16 i = 0; i < num_flows; i++) {
1779                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1780                                 switch (flows[i].t) {
1781                                         case NEIGHBOR_UPPER:
1782                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1783                                                         max_node_level = LIQUID_LEVEL_MAX;
1784                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1785                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1786                                                 } else if (nb_liquid_level > max_node_level)
1787                                                         max_node_level = nb_liquid_level;
1788                                                 break;
1789                                         case NEIGHBOR_LOWER:
1790                                                 break;
1791                                         case NEIGHBOR_SAME_LEVEL:
1792                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1793                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1794                                                         max_node_level = nb_liquid_level - 1;
1795                                                 }
1796                                                 break;
1797                                 }
1798                         }
1799
1800                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1801                         if (viscosity > 1 && max_node_level != liquid_level) {
1802                                 // amount to gain, limited by viscosity
1803                                 // must be at least 1 in absolute value
1804                                 s8 level_inc = max_node_level - liquid_level;
1805                                 if (level_inc < -viscosity || level_inc > viscosity)
1806                                         new_node_level = liquid_level + level_inc/viscosity;
1807                                 else if (level_inc < 0)
1808                                         new_node_level = liquid_level - 1;
1809                                 else if (level_inc > 0)
1810                                         new_node_level = liquid_level + 1;
1811                                 if (new_node_level != max_node_level)
1812                                         must_reflow.push_back(p0);
1813                         } else
1814                                 new_node_level = max_node_level;
1815
1816                         if (max_node_level >= (LIQUID_LEVEL_MAX+1-range))
1817                                 new_node_content = liquid_kind;
1818                         else
1819                                 new_node_content = CONTENT_AIR;
1820
1821                 }
1822
1823                 /*
1824                         check if anything has changed. if not, just continue with the next node.
1825                  */
1826                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1827                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1828                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1829                                                                                  == flowing_down)))
1830                         continue;
1831
1832
1833                 /*
1834                         update the current node
1835                  */
1836                 MapNode n00 = n0;
1837                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1838                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1839                         // set level to last 3 bits, flowing down bit to 4th bit
1840                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1841                 } else {
1842                         // set the liquid level and flow bit to 0
1843                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1844                 }
1845                 n0.setContent(new_node_content);
1846
1847                 // Find out whether there is a suspect for this action
1848                 std::string suspect;
1849                 if(m_gamedef->rollback()){
1850                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1851                 }
1852
1853                 if(!suspect.empty()){
1854                         // Blame suspect
1855                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1856                         // Get old node for rollback
1857                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
1858                         // Set node
1859                         setNode(p0, n0);
1860                         // Report
1861                         RollbackNode rollback_newnode(this, p0, m_gamedef);
1862                         RollbackAction action;
1863                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1864                         m_gamedef->rollback()->reportAction(action);
1865                 } else {
1866                         // Set node
1867                         setNode(p0, n0);
1868                 }
1869
1870                 v3s16 blockpos = getNodeBlockPos(p0);
1871                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1872                 if(block != NULL) {
1873                         modified_blocks[blockpos] =  block;
1874                         // If new or old node emits light, MapBlock requires lighting update
1875                         if(nodemgr->get(n0).light_source != 0 ||
1876                                         nodemgr->get(n00).light_source != 0)
1877                                 lighting_modified_blocks[block->getPos()] = block;
1878                 }
1879
1880                 /*
1881                         enqueue neighbors for update if neccessary
1882                  */
1883                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1884                         case LIQUID_SOURCE:
1885                         case LIQUID_FLOWING:
1886                                 // make sure source flows into all neighboring nodes
1887                                 for (u16 i = 0; i < num_flows; i++)
1888                                         if (flows[i].t != NEIGHBOR_UPPER)
1889                                                 m_transforming_liquid.push_back(flows[i].p);
1890                                 for (u16 i = 0; i < num_airs; i++)
1891                                         if (airs[i].t != NEIGHBOR_UPPER)
1892                                                 m_transforming_liquid.push_back(airs[i].p);
1893                                 break;
1894                         case LIQUID_NONE:
1895                                 // this flow has turned to air; neighboring flows might need to do the same
1896                                 for (u16 i = 0; i < num_flows; i++)
1897                                         m_transforming_liquid.push_back(flows[i].p);
1898                                 break;
1899                 }
1900         }
1901         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1902         while (must_reflow.size() > 0)
1903                 m_transforming_liquid.push_back(must_reflow.pop_front());
1904         updateLighting(lighting_modified_blocks, modified_blocks);
1905 }
1906
1907 NodeMetadata *Map::getNodeMetadata(v3s16 p)
1908 {
1909         v3s16 blockpos = getNodeBlockPos(p);
1910         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1911         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1912         if(!block){
1913                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1914                                 <<PP(blockpos)<<std::endl;
1915                 block = emergeBlock(blockpos, false);
1916         }
1917         if(!block){
1918                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
1919                                 <<std::endl;
1920                 return NULL;
1921         }
1922         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1923         return meta;
1924 }
1925
1926 bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1927 {
1928         v3s16 blockpos = getNodeBlockPos(p);
1929         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1930         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1931         if(!block){
1932                 infostream<<"Map::setNodeMetadata(): Need to emerge "
1933                                 <<PP(blockpos)<<std::endl;
1934                 block = emergeBlock(blockpos, false);
1935         }
1936         if(!block){
1937                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
1938                                 <<std::endl;
1939                 return false;
1940         }
1941         block->m_node_metadata.set(p_rel, meta);
1942         return true;
1943 }
1944
1945 void Map::removeNodeMetadata(v3s16 p)
1946 {
1947         v3s16 blockpos = getNodeBlockPos(p);
1948         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1949         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1950         if(block == NULL)
1951         {
1952                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1953                                 <<std::endl;
1954                 return;
1955         }
1956         block->m_node_metadata.remove(p_rel);
1957 }
1958
1959 NodeTimer Map::getNodeTimer(v3s16 p)
1960 {
1961         v3s16 blockpos = getNodeBlockPos(p);
1962         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1963         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1964         if(!block){
1965                 infostream<<"Map::getNodeTimer(): Need to emerge "
1966                                 <<PP(blockpos)<<std::endl;
1967                 block = emergeBlock(blockpos, false);
1968         }
1969         if(!block){
1970                 infostream<<"WARNING: Map::getNodeTimer(): Block not found"
1971                                 <<std::endl;
1972                 return NodeTimer();
1973         }
1974         NodeTimer t = block->m_node_timers.get(p_rel);
1975         return t;
1976 }
1977
1978 void Map::setNodeTimer(v3s16 p, NodeTimer t)
1979 {
1980         v3s16 blockpos = getNodeBlockPos(p);
1981         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1982         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1983         if(!block){
1984                 infostream<<"Map::setNodeTimer(): Need to emerge "
1985                                 <<PP(blockpos)<<std::endl;
1986                 block = emergeBlock(blockpos, false);
1987         }
1988         if(!block){
1989                 infostream<<"WARNING: Map::setNodeTimer(): Block not found"
1990                                 <<std::endl;
1991                 return;
1992         }
1993         block->m_node_timers.set(p_rel, t);
1994 }
1995
1996 void Map::removeNodeTimer(v3s16 p)
1997 {
1998         v3s16 blockpos = getNodeBlockPos(p);
1999         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
2000         MapBlock *block = getBlockNoCreateNoEx(blockpos);
2001         if(block == NULL)
2002         {
2003                 infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
2004                                 <<std::endl;
2005                 return;
2006         }
2007         block->m_node_timers.remove(p_rel);
2008 }
2009
2010 /*
2011         ServerMap
2012 */
2013 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
2014         Map(dout_server, gamedef),
2015         m_emerge(emerge),
2016         m_map_metadata_changed(true)
2017 {
2018         verbosestream<<__FUNCTION_NAME<<std::endl;
2019
2020         /*
2021                 Try to load map; if not found, create a new one.
2022         */
2023
2024         // Determine which database backend to use
2025         std::string conf_path = savedir + DIR_DELIM + "world.mt";
2026         Settings conf;
2027         bool succeeded = conf.readConfigFile(conf_path.c_str());
2028         if (!succeeded || !conf.exists("backend")) {
2029                 // fall back to sqlite3
2030                 dbase = new Database_SQLite3(this, savedir);
2031                 conf.set("backend", "sqlite3");
2032         } else {
2033                 std::string backend = conf.get("backend");
2034                 if (backend == "dummy")
2035                         dbase = new Database_Dummy(this);
2036                 else if (backend == "sqlite3")
2037                         dbase = new Database_SQLite3(this, savedir);
2038                 #if USE_LEVELDB
2039                 else if (backend == "leveldb")
2040                         dbase = new Database_LevelDB(this, savedir);
2041                 #endif
2042                 #if USE_REDIS
2043                 else if (backend == "redis")
2044                         dbase = new Database_Redis(this, savedir);
2045                 #endif
2046                 else
2047                         throw BaseException("Unknown map backend");
2048         }
2049
2050         m_savedir = savedir;
2051         m_map_saving_enabled = false;
2052
2053         try
2054         {
2055                 // If directory exists, check contents and load if possible
2056                 if(fs::PathExists(m_savedir))
2057                 {
2058                         // If directory is empty, it is safe to save into it.
2059                         if(fs::GetDirListing(m_savedir).size() == 0)
2060                         {
2061                                 infostream<<"ServerMap: Empty save directory is valid."
2062                                                 <<std::endl;
2063                                 m_map_saving_enabled = true;
2064                         }
2065                         else
2066                         {
2067                                 try{
2068                                         // Load map metadata (seed, chunksize)
2069                                         loadMapMeta();
2070                                 }
2071                                 catch(SettingNotFoundException &e){
2072                                         infostream<<"ServerMap:  Some metadata not found."
2073                                                           <<" Using default settings."<<std::endl;
2074                                 }
2075                                 catch(FileNotGoodException &e){
2076                                         infostream<<"WARNING: Could not load map metadata"
2077                                                         //<<" Disabling chunk-based generator."
2078                                                         <<std::endl;
2079                                         //m_chunksize = 0;
2080                                 }
2081
2082                                 infostream<<"ServerMap: Successfully loaded map "
2083                                                 <<"metadata from "<<savedir
2084                                                 <<", assuming valid save directory."
2085                                                 <<" seed="<< m_emerge->params.seed <<"."
2086                                                 <<std::endl;
2087
2088                                 m_map_saving_enabled = true;
2089                                 // Map loaded, not creating new one
2090                                 return;
2091                         }
2092                 }
2093                 // If directory doesn't exist, it is safe to save to it
2094                 else{
2095                         m_map_saving_enabled = true;
2096                 }
2097         }
2098         catch(std::exception &e)
2099         {
2100                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
2101                                 <<", exception: "<<e.what()<<std::endl;
2102                 infostream<<"Please remove the map or fix it."<<std::endl;
2103                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2104         }
2105
2106         infostream<<"Initializing new map."<<std::endl;
2107
2108         // Create zero sector
2109         emergeSector(v2s16(0,0));
2110
2111         // Initially write whole map
2112         save(MOD_STATE_CLEAN);
2113 }
2114
2115 ServerMap::~ServerMap()
2116 {
2117         verbosestream<<__FUNCTION_NAME<<std::endl;
2118
2119         try
2120         {
2121                 if(m_map_saving_enabled)
2122                 {
2123                         // Save only changed parts
2124                         save(MOD_STATE_WRITE_AT_UNLOAD);
2125                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2126                 }
2127                 else
2128                 {
2129                         infostream<<"ServerMap: Map not saved"<<std::endl;
2130                 }
2131         }
2132         catch(std::exception &e)
2133         {
2134                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2135                                 <<", exception: "<<e.what()<<std::endl;
2136         }
2137
2138         /*
2139                 Close database if it was opened
2140         */
2141         delete dbase;
2142
2143 #if 0
2144         /*
2145                 Free all MapChunks
2146         */
2147         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2148         for(; i.atEnd() == false; i++)
2149         {
2150                 MapChunk *chunk = i.getNode()->getValue();
2151                 delete chunk;
2152         }
2153 #endif
2154 }
2155
2156 u64 ServerMap::getSeed()
2157 {
2158         return m_emerge->params.seed;
2159 }
2160
2161 s16 ServerMap::getWaterLevel()
2162 {
2163         return m_emerge->params.water_level;
2164 }
2165
2166 bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
2167 {
2168         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2169         EMERGE_DBG_OUT("initBlockMake(): " PP(blockpos) " - " PP(blockpos));
2170
2171         s16 chunksize = m_emerge->params.chunksize;
2172         s16 coffset = -chunksize / 2;
2173         v3s16 chunk_offset(coffset, coffset, coffset);
2174         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2175         v3s16 blockpos_min = blockpos_div * chunksize;
2176         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2177         blockpos_min += chunk_offset;
2178         blockpos_max += chunk_offset;
2179
2180         v3s16 extra_borders(1,1,1);
2181
2182         // Do nothing if not inside limits (+-1 because of neighbors)
2183         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2184                 blockpos_over_limit(blockpos_max + extra_borders))
2185                 return false;
2186
2187         data->seed = m_emerge->params.seed;
2188         data->blockpos_min = blockpos_min;
2189         data->blockpos_max = blockpos_max;
2190         data->blockpos_requested = blockpos;
2191         data->nodedef = m_gamedef->ndef();
2192
2193         /*
2194                 Create the whole area of this and the neighboring blocks
2195         */
2196         {
2197                 //TimeTaker timer("initBlockMake() create area");
2198
2199                 for(s16 x=blockpos_min.X-extra_borders.X;
2200                                 x<=blockpos_max.X+extra_borders.X; x++)
2201                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2202                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2203                 {
2204                         v2s16 sectorpos(x, z);
2205                         // Sector metadata is loaded from disk if not already loaded.
2206                         ServerMapSector *sector = createSector(sectorpos);
2207                         assert(sector);
2208                         (void) sector;
2209
2210                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2211                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2212                         {
2213                                 v3s16 p(x,y,z);
2214                                 //MapBlock *block = createBlock(p);
2215                                 // 1) get from memory, 2) load from disk
2216                                 MapBlock *block = emergeBlock(p, false);
2217                                 // 3) create a blank one
2218                                 if(block == NULL)
2219                                 {
2220                                         block = createBlock(p);
2221
2222                                         /*
2223                                                 Block gets sunlight if this is true.
2224
2225                                                 Refer to the map generator heuristics.
2226                                         */
2227                                         bool ug = m_emerge->isBlockUnderground(p);
2228                                         block->setIsUnderground(ug);
2229                                 }
2230
2231                                 // Lighting will not be valid after make_chunk is called
2232                                 block->setLightingExpired(true);
2233                                 // Lighting will be calculated
2234                                 //block->setLightingExpired(false);
2235                         }
2236                 }
2237         }
2238
2239         /*
2240                 Now we have a big empty area.
2241
2242                 Make a ManualMapVoxelManipulator that contains this and the
2243                 neighboring blocks
2244         */
2245
2246         // The area that contains this block and it's neighbors
2247         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2248         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2249
2250         data->vmanip = new ManualMapVoxelManipulator(this);
2251         //data->vmanip->setMap(this);
2252
2253         // Add the area
2254         {
2255                 //TimeTaker timer("initBlockMake() initialEmerge");
2256                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max, false);
2257         }
2258         
2259         // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
2260 /*      for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2261                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2262                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2263                                 core::map<v3s16, u8>::Node *n;
2264                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2265                                 if (n == NULL)
2266                                         continue;
2267                                 u8 flags = n->getValue();
2268                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2269                                 n->setValue(flags);
2270                         }
2271                 }
2272         }*/
2273
2274         // Data is ready now.
2275         return true;
2276 }
2277
2278 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
2279                 std::map<v3s16, MapBlock*> &changed_blocks)
2280 {
2281         v3s16 blockpos_min = data->blockpos_min;
2282         v3s16 blockpos_max = data->blockpos_max;
2283         v3s16 blockpos_requested = data->blockpos_requested;
2284         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2285                         <<blockpos_requested.Y<<","
2286                         <<blockpos_requested.Z<<")"<<std::endl;*/
2287
2288         v3s16 extra_borders(1,1,1);
2289
2290         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2291
2292         /*infostream<<"Resulting vmanip:"<<std::endl;
2293         data->vmanip.print(infostream);*/
2294
2295         // Make sure affected blocks are loaded
2296         for(s16 x=blockpos_min.X-extra_borders.X;
2297                         x<=blockpos_max.X+extra_borders.X; x++)
2298         for(s16 z=blockpos_min.Z-extra_borders.Z;
2299                         z<=blockpos_max.Z+extra_borders.Z; z++)
2300         for(s16 y=blockpos_min.Y-extra_borders.Y;
2301                         y<=blockpos_max.Y+extra_borders.Y; y++)
2302         {
2303                 v3s16 p(x, y, z);
2304                 // Load from disk if not already in memory
2305                 emergeBlock(p, false);
2306         }
2307
2308         /*
2309                 Blit generated stuff to map
2310                 NOTE: blitBackAll adds nearly everything to changed_blocks
2311         */
2312         {
2313                 // 70ms @cs=8
2314                 //TimeTaker timer("finishBlockMake() blitBackAll");
2315                 data->vmanip->blitBackAll(&changed_blocks);
2316         }
2317
2318         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
2319
2320         /*
2321                 Copy transforming liquid information
2322         */
2323         while(data->transforming_liquid.size() > 0)
2324         {
2325                 v3s16 p = data->transforming_liquid.pop_front();
2326                 m_transforming_liquid.push_back(p);
2327         }
2328
2329         /*
2330                 Do stuff in central blocks
2331         */
2332
2333         /*
2334                 Update lighting
2335         */
2336         {
2337 #if 0
2338                 TimeTaker t("finishBlockMake lighting update");
2339
2340                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2341
2342                 // Center blocks
2343                 for(s16 x=blockpos_min.X-extra_borders.X;
2344                                 x<=blockpos_max.X+extra_borders.X; x++)
2345                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2346                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2347                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2348                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2349                 {
2350                         v3s16 p(x, y, z);
2351                         MapBlock *block = getBlockNoCreateNoEx(p);
2352                         assert(block);
2353                         lighting_update_blocks.insert(block->getPos(), block);
2354                 }
2355
2356                 updateLighting(lighting_update_blocks, changed_blocks);
2357 #endif
2358
2359                 /*
2360                         Set lighting to non-expired state in all of them.
2361                         This is cheating, but it is not fast enough if all of them
2362                         would actually be updated.
2363                 */
2364                 for(s16 x=blockpos_min.X-extra_borders.X;
2365                                 x<=blockpos_max.X+extra_borders.X; x++)
2366                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2367                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2368                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2369                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2370                 {
2371                         v3s16 p(x, y, z);
2372                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2373                 }
2374
2375 #if 0
2376                 if(enable_mapgen_debug_info == false)
2377                         t.stop(true); // Hide output
2378 #endif
2379         }
2380
2381         /*
2382                 Go through changed blocks
2383         */
2384         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2385                         i != changed_blocks.end(); ++i)
2386         {
2387                 MapBlock *block = i->second;
2388                 assert(block);
2389                 /*
2390                         Update day/night difference cache of the MapBlocks
2391                 */
2392                 block->expireDayNightDiff();
2393                 /*
2394                         Set block as modified
2395                 */
2396                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2397                                 "finishBlockMake expireDayNightDiff");
2398         }
2399
2400         /*
2401                 Set central blocks as generated
2402         */
2403         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2404         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2405         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2406         {
2407                 v3s16 p(x, y, z);
2408                 MapBlock *block = getBlockNoCreateNoEx(p);
2409                 assert(block);
2410                 block->setGenerated(true);
2411         }
2412
2413         /*
2414                 Save changed parts of map
2415                 NOTE: Will be saved later.
2416         */
2417         //save(MOD_STATE_WRITE_AT_UNLOAD);
2418
2419         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2420                         <<","<<blockpos_requested.Y<<","
2421                         <<blockpos_requested.Z<<")"<<std::endl;*/
2422                         
2423         
2424 #if 0
2425         if(enable_mapgen_debug_info)
2426         {
2427                 /*
2428                         Analyze resulting blocks
2429                 */
2430                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2431                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2432                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2433                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2434                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2435                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2436                 {
2437                         v3s16 p = v3s16(x,y,z);
2438                         MapBlock *block = getBlockNoCreateNoEx(p);
2439                         char spos[20];
2440                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2441                         infostream<<"Generated "<<spos<<": "
2442                                         <<analyze_block(block)<<std::endl;
2443                 }
2444         }
2445 #endif
2446
2447         MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
2448         assert(block);
2449
2450         return block;
2451 }
2452
2453 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2454 {
2455         DSTACKF("%s: p2d=(%d,%d)",
2456                         __FUNCTION_NAME,
2457                         p2d.X, p2d.Y);
2458
2459         /*
2460                 Check if it exists already in memory
2461         */
2462         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2463         if(sector != NULL)
2464                 return sector;
2465
2466         /*
2467                 Try to load it from disk (with blocks)
2468         */
2469         //if(loadSectorFull(p2d) == true)
2470
2471         /*
2472                 Try to load metadata from disk
2473         */
2474 #if 0
2475         if(loadSectorMeta(p2d) == true)
2476         {
2477                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2478                 if(sector == NULL)
2479                 {
2480                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2481                         throw InvalidPositionException("");
2482                 }
2483                 return sector;
2484         }
2485 #endif
2486         /*
2487                 Do not create over-limit
2488         */
2489         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2490         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2491         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2492         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2493                 throw InvalidPositionException("createSector(): pos. over limit");
2494
2495         /*
2496                 Generate blank sector
2497         */
2498
2499         sector = new ServerMapSector(this, p2d, m_gamedef);
2500
2501         // Sector position on map in nodes
2502         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2503
2504         /*
2505                 Insert to container
2506         */
2507         m_sectors[p2d] = sector;
2508
2509         return sector;
2510 }
2511
2512 #if 0
2513 /*
2514         This is a quick-hand function for calling makeBlock().
2515 */
2516 MapBlock * ServerMap::generateBlock(
2517                 v3s16 p,
2518                 std::map<v3s16, MapBlock*> &modified_blocks
2519 )
2520 {
2521         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2522
2523         /*infostream<<"generateBlock(): "
2524                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2525                         <<std::endl;*/
2526
2527         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2528
2529         TimeTaker timer("generateBlock");
2530
2531         //MapBlock *block = original_dummy;
2532
2533         v2s16 p2d(p.X, p.Z);
2534         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2535
2536         /*
2537                 Do not generate over-limit
2538         */
2539         if(blockpos_over_limit(p))
2540         {
2541                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2542                 throw InvalidPositionException("generateBlock(): pos. over limit");
2543         }
2544
2545         /*
2546                 Create block make data
2547         */
2548         BlockMakeData data;
2549         initBlockMake(&data, p);
2550
2551         /*
2552                 Generate block
2553         */
2554         {
2555                 TimeTaker t("mapgen::make_block()");
2556                 mapgen->makeChunk(&data);
2557                 //mapgen::make_block(&data);
2558
2559                 if(enable_mapgen_debug_info == false)
2560                         t.stop(true); // Hide output
2561         }
2562
2563         /*
2564                 Blit data back on map, update lighting, add mobs and whatever this does
2565         */
2566         finishBlockMake(&data, modified_blocks);
2567
2568         /*
2569                 Get central block
2570         */
2571         MapBlock *block = getBlockNoCreateNoEx(p);
2572
2573 #if 0
2574         /*
2575                 Check result
2576         */
2577         if(block)
2578         {
2579                 bool erroneus_content = false;
2580                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2581                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2582                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2583                 {
2584                         v3s16 p(x0,y0,z0);
2585                         MapNode n = block->getNode(p);
2586                         if(n.getContent() == CONTENT_IGNORE)
2587                         {
2588                                 infostream<<"CONTENT_IGNORE at "
2589                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2590                                                 <<std::endl;
2591                                 erroneus_content = true;
2592                                 assert(0);
2593                         }
2594                 }
2595                 if(erroneus_content)
2596                 {
2597                         assert(0);
2598                 }
2599         }
2600 #endif
2601
2602 #if 0
2603         /*
2604                 Generate a completely empty block
2605         */
2606         if(block)
2607         {
2608                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2609                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2610                 {
2611                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2612                         {
2613                                 MapNode n;
2614                                 n.setContent(CONTENT_AIR);
2615                                 block->setNode(v3s16(x0,y0,z0), n);
2616                         }
2617                 }
2618         }
2619 #endif
2620
2621         if(enable_mapgen_debug_info == false)
2622                 timer.stop(true); // Hide output
2623
2624         return block;
2625 }
2626 #endif
2627
2628 MapBlock * ServerMap::createBlock(v3s16 p)
2629 {
2630         DSTACKF("%s: p=(%d,%d,%d)",
2631                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2632
2633         /*
2634                 Do not create over-limit
2635         */
2636         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2637         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2638         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2639         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2640         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2641         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2642                 throw InvalidPositionException("createBlock(): pos. over limit");
2643
2644         v2s16 p2d(p.X, p.Z);
2645         s16 block_y = p.Y;
2646         /*
2647                 This will create or load a sector if not found in memory.
2648                 If block exists on disk, it will be loaded.
2649
2650                 NOTE: On old save formats, this will be slow, as it generates
2651                       lighting on blocks for them.
2652         */
2653         ServerMapSector *sector;
2654         try{
2655                 sector = (ServerMapSector*)createSector(p2d);
2656                 assert(sector->getId() == MAPSECTOR_SERVER);
2657         }
2658         catch(InvalidPositionException &e)
2659         {
2660                 infostream<<"createBlock: createSector() failed"<<std::endl;
2661                 throw e;
2662         }
2663         /*
2664                 NOTE: This should not be done, or at least the exception
2665                 should not be passed on as std::exception, because it
2666                 won't be catched at all.
2667         */
2668         /*catch(std::exception &e)
2669         {
2670                 infostream<<"createBlock: createSector() failed: "
2671                                 <<e.what()<<std::endl;
2672                 throw e;
2673         }*/
2674
2675         /*
2676                 Try to get a block from the sector
2677         */
2678
2679         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2680         if(block)
2681         {
2682                 if(block->isDummy())
2683                         block->unDummify();
2684                 return block;
2685         }
2686         // Create blank
2687         block = sector->createBlankBlock(block_y);
2688
2689         return block;
2690 }
2691
2692 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2693 {
2694         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2695                         __FUNCTION_NAME,
2696                         p.X, p.Y, p.Z, create_blank);
2697
2698         {
2699                 MapBlock *block = getBlockNoCreateNoEx(p);
2700                 if(block && block->isDummy() == false)
2701                         return block;
2702         }
2703
2704         {
2705                 MapBlock *block = loadBlock(p);
2706                 if(block)
2707                         return block;
2708         }
2709
2710         if (create_blank) {
2711                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2712                 MapBlock *block = sector->createBlankBlock(p.Y);
2713
2714                 return block;
2715         }
2716
2717 #if 0
2718         if(allow_generate)
2719         {
2720                 std::map<v3s16, MapBlock*> modified_blocks;
2721                 MapBlock *block = generateBlock(p, modified_blocks);
2722                 if(block)
2723                 {
2724                         MapEditEvent event;
2725                         event.type = MEET_OTHER;
2726                         event.p = p;
2727
2728                         // Copy modified_blocks to event
2729                         for(std::map<v3s16, MapBlock*>::iterator
2730                                         i = modified_blocks.begin();
2731                                         i != modified_blocks.end(); ++i)
2732                         {
2733                                 event.modified_blocks.insert(i->first);
2734                         }
2735
2736                         // Queue event
2737                         dispatchEvent(&event);
2738
2739                         return block;
2740                 }
2741         }
2742 #endif
2743
2744         return NULL;
2745 }
2746
2747 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
2748 {
2749         MapBlock *block = getBlockNoCreateNoEx(p3d);
2750         if (block == NULL)
2751                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
2752
2753         return block;
2754 }
2755
2756 void ServerMap::prepareBlock(MapBlock *block) {
2757 }
2758
2759 s16 ServerMap::findGroundLevel(v2s16 p2d)
2760 {
2761 #if 0
2762         /*
2763                 Uh, just do something random...
2764         */
2765         // Find existing map from top to down
2766         s16 max=63;
2767         s16 min=-64;
2768         v3s16 p(p2d.X, max, p2d.Y);
2769         for(; p.Y>min; p.Y--)
2770         {
2771                 MapNode n = getNodeNoEx(p);
2772                 if(n.getContent() != CONTENT_IGNORE)
2773                         break;
2774         }
2775         if(p.Y == min)
2776                 goto plan_b;
2777         // If this node is not air, go to plan b
2778         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2779                 goto plan_b;
2780         // Search existing walkable and return it
2781         for(; p.Y>min; p.Y--)
2782         {
2783                 MapNode n = getNodeNoEx(p);
2784                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2785                         return p.Y;
2786         }
2787
2788         // Move to plan b
2789 plan_b:
2790 #endif
2791
2792         /*
2793                 Determine from map generator noise functions
2794         */
2795
2796         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2797         return level;
2798
2799         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2800         //return (s16)level;
2801 }
2802
2803 bool ServerMap::loadFromFolders() {
2804         if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ?
2805                 return true;
2806         return false;
2807 }
2808
2809 void ServerMap::createDirs(std::string path)
2810 {
2811         if(fs::CreateAllDirs(path) == false)
2812         {
2813                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2814                                 <<"\""<<path<<"\""<<std::endl;
2815                 throw BaseException("ServerMap failed to create directory");
2816         }
2817 }
2818
2819 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2820 {
2821         char cc[9];
2822         switch(layout)
2823         {
2824                 case 1:
2825                         snprintf(cc, 9, "%.4x%.4x",
2826                                 (unsigned int)pos.X&0xffff,
2827                                 (unsigned int)pos.Y&0xffff);
2828
2829                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2830                 case 2:
2831                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2832                                 (unsigned int)pos.X&0xfff,
2833                                 (unsigned int)pos.Y&0xfff);
2834
2835                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2836                 default:
2837                         assert(false);
2838                         return "";
2839         }
2840 }
2841
2842 v2s16 ServerMap::getSectorPos(std::string dirname)
2843 {
2844         unsigned int x = 0, y = 0;
2845         int r;
2846         std::string component;
2847         fs::RemoveLastPathComponent(dirname, &component, 1);
2848         if(component.size() == 8)
2849         {
2850                 // Old layout
2851                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
2852         }
2853         else if(component.size() == 3)
2854         {
2855                 // New layout
2856                 fs::RemoveLastPathComponent(dirname, &component, 2);
2857                 r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2858                 // Sign-extend the 12 bit values up to 16 bits...
2859                 if(x&0x800) x|=0xF000;
2860                 if(y&0x800) y|=0xF000;
2861         }
2862         else
2863         {
2864                 assert(false);
2865         }
2866         assert(r == 2);
2867         v2s16 pos((s16)x, (s16)y);
2868         return pos;
2869 }
2870
2871 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2872 {
2873         v2s16 p2d = getSectorPos(sectordir);
2874
2875         if(blockfile.size() != 4){
2876                 throw InvalidFilenameException("Invalid block filename");
2877         }
2878         unsigned int y;
2879         int r = sscanf(blockfile.c_str(), "%4x", &y);
2880         if(r != 1)
2881                 throw InvalidFilenameException("Invalid block filename");
2882         return v3s16(p2d.X, y, p2d.Y);
2883 }
2884
2885 std::string ServerMap::getBlockFilename(v3s16 p)
2886 {
2887         char cc[5];
2888         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2889         return cc;
2890 }
2891
2892 void ServerMap::save(ModifiedState save_level)
2893 {
2894         DSTACK(__FUNCTION_NAME);
2895         if(m_map_saving_enabled == false)
2896         {
2897                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2898                 return;
2899         }
2900
2901         if(save_level == MOD_STATE_CLEAN)
2902                 infostream<<"ServerMap: Saving whole map, this can take time."
2903                                 <<std::endl;
2904
2905         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
2906         {
2907                 saveMapMeta();
2908         }
2909
2910         // Profile modified reasons
2911         Profiler modprofiler;
2912
2913         u32 sector_meta_count = 0;
2914         u32 block_count = 0;
2915         u32 block_count_all = 0; // Number of blocks in memory
2916
2917         // Don't do anything with sqlite unless something is really saved
2918         bool save_started = false;
2919
2920         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
2921                 i != m_sectors.end(); ++i)
2922         {
2923                 ServerMapSector *sector = (ServerMapSector*)i->second;
2924                 assert(sector->getId() == MAPSECTOR_SERVER);
2925
2926                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
2927                 {
2928                         saveSectorMeta(sector);
2929                         sector_meta_count++;
2930                 }
2931                 std::list<MapBlock*> blocks;
2932                 sector->getBlocks(blocks);
2933
2934                 for(std::list<MapBlock*>::iterator j = blocks.begin();
2935                         j != blocks.end(); ++j)
2936                 {
2937                         MapBlock *block = *j;
2938
2939                         block_count_all++;
2940
2941                         if(block->getModified() >= (u32)save_level)
2942                         {
2943                                 // Lazy beginSave()
2944                                 if(!save_started){
2945                                         beginSave();
2946                                         save_started = true;
2947                                 }
2948
2949                                 modprofiler.add(block->getModifiedReason(), 1);
2950
2951                                 saveBlock(block);
2952                                 block_count++;
2953
2954                                 /*infostream<<"ServerMap: Written block ("
2955                                                 <<block->getPos().X<<","
2956                                                 <<block->getPos().Y<<","
2957                                                 <<block->getPos().Z<<")"
2958                                                 <<std::endl;*/
2959                         }
2960                 }
2961         }
2962         if(save_started)
2963                 endSave();
2964
2965         /*
2966                 Only print if something happened or saved whole map
2967         */
2968         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
2969                         || block_count != 0)
2970         {
2971                 infostream<<"ServerMap: Written: "
2972                                 <<sector_meta_count<<" sector metadata files, "
2973                                 <<block_count<<" block files"
2974                                 <<", "<<block_count_all<<" blocks in memory."
2975                                 <<std::endl;
2976                 PrintInfo(infostream); // ServerMap/ClientMap:
2977                 infostream<<"Blocks modified by: "<<std::endl;
2978                 modprofiler.print(infostream);
2979         }
2980 }
2981
2982 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
2983 {
2984         if(loadFromFolders()){
2985                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
2986                                 <<"all blocks that are stored in flat files"<<std::endl;
2987         }
2988         dbase->listAllLoadableBlocks(dst);
2989 }
2990
2991 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
2992 {
2993         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
2994                 si != m_sectors.end(); ++si)
2995         {
2996                 MapSector *sector = si->second;
2997
2998                 std::list<MapBlock*> blocks;
2999                 sector->getBlocks(blocks);
3000
3001                 for(std::list<MapBlock*>::iterator i = blocks.begin();
3002                                 i != blocks.end(); ++i)
3003                 {
3004                         MapBlock *block = (*i);
3005                         v3s16 p = block->getPos();
3006                         dst.push_back(p);
3007                 }
3008         }
3009 }
3010
3011 void ServerMap::saveMapMeta()
3012 {
3013         DSTACK(__FUNCTION_NAME);
3014
3015         /*infostream<<"ServerMap::saveMapMeta(): "
3016                         <<"seed="<<m_seed
3017                         <<std::endl;*/
3018
3019         createDirs(m_savedir);
3020
3021         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3022         std::ostringstream ss(std::ios_base::binary);
3023
3024         Settings params;
3025
3026         m_emerge->saveParamsToSettings(&params);
3027         params.writeLines(ss);
3028
3029         ss<<"[end_of_params]\n";
3030
3031         if(!fs::safeWriteToFile(fullpath, ss.str()))
3032         {
3033                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3034                                 <<"could not write "<<fullpath<<std::endl;
3035                 throw FileNotGoodException("Cannot save chunk metadata");
3036         }
3037
3038         m_map_metadata_changed = false;
3039 }
3040
3041 void ServerMap::loadMapMeta()
3042 {
3043         DSTACK(__FUNCTION_NAME);
3044
3045         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3046                         <<std::endl;*/
3047
3048         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3049         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3050         if(is.good() == false)
3051         {
3052                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3053                                 <<"could not open"<<fullpath<<std::endl;
3054                 throw FileNotGoodException("Cannot open map metadata");
3055         }
3056
3057         Settings params;
3058
3059         for(;;)
3060         {
3061                 if(is.eof())
3062                         throw SerializationError
3063                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3064                 std::string line;
3065                 std::getline(is, line);
3066                 std::string trimmedline = trim(line);
3067                 if(trimmedline == "[end_of_params]")
3068                         break;
3069                 params.parseConfigLine(line);
3070         }
3071         
3072         m_emerge->loadParamsFromSettings(&params);
3073
3074         verbosestream<<"ServerMap::loadMapMeta(): seed="
3075                 << m_emerge->params.seed<<std::endl;
3076 }
3077
3078 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3079 {
3080         DSTACK(__FUNCTION_NAME);
3081         // Format used for writing
3082         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3083         // Get destination
3084         v2s16 pos = sector->getPos();
3085         std::string dir = getSectorDir(pos);
3086         createDirs(dir);
3087
3088         std::string fullpath = dir + DIR_DELIM + "meta";
3089         std::ostringstream ss(std::ios_base::binary);
3090
3091         sector->serialize(ss, version);
3092
3093         if(!fs::safeWriteToFile(fullpath, ss.str()))
3094                 throw FileNotGoodException("Cannot write sector metafile");
3095
3096         sector->differs_from_disk = false;
3097 }
3098
3099 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3100 {
3101         DSTACK(__FUNCTION_NAME);
3102         // Get destination
3103         v2s16 p2d = getSectorPos(sectordir);
3104
3105         ServerMapSector *sector = NULL;
3106
3107         std::string fullpath = sectordir + DIR_DELIM + "meta";
3108         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3109         if(is.good() == false)
3110         {
3111                 // If the directory exists anyway, it probably is in some old
3112                 // format. Just go ahead and create the sector.
3113                 if(fs::PathExists(sectordir))
3114                 {
3115                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3116                                         <<fullpath<<" doesn't exist but directory does."
3117                                         <<" Continuing with a sector with no metadata."
3118                                         <<std::endl;*/
3119                         sector = new ServerMapSector(this, p2d, m_gamedef);
3120                         m_sectors[p2d] = sector;
3121                 }
3122                 else
3123                 {
3124                         throw FileNotGoodException("Cannot open sector metafile");
3125                 }
3126         }
3127         else
3128         {
3129                 sector = ServerMapSector::deSerialize
3130                                 (is, this, p2d, m_sectors, m_gamedef);
3131                 if(save_after_load)
3132                         saveSectorMeta(sector);
3133         }
3134
3135         sector->differs_from_disk = false;
3136
3137         return sector;
3138 }
3139
3140 bool ServerMap::loadSectorMeta(v2s16 p2d)
3141 {
3142         DSTACK(__FUNCTION_NAME);
3143
3144         MapSector *sector = NULL;
3145
3146         // The directory layout we're going to load from.
3147         //  1 - original sectors/xxxxzzzz/
3148         //  2 - new sectors2/xxx/zzz/
3149         //  If we load from anything but the latest structure, we will
3150         //  immediately save to the new one, and remove the old.
3151         int loadlayout = 1;
3152         std::string sectordir1 = getSectorDir(p2d, 1);
3153         std::string sectordir;
3154         if(fs::PathExists(sectordir1))
3155         {
3156                 sectordir = sectordir1;
3157         }
3158         else
3159         {
3160                 loadlayout = 2;
3161                 sectordir = getSectorDir(p2d, 2);
3162         }
3163
3164         try{
3165                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3166         }
3167         catch(InvalidFilenameException &e)
3168         {
3169                 return false;
3170         }
3171         catch(FileNotGoodException &e)
3172         {
3173                 return false;
3174         }
3175         catch(std::exception &e)
3176         {
3177                 return false;
3178         }
3179
3180         return true;
3181 }
3182
3183 #if 0
3184 bool ServerMap::loadSectorFull(v2s16 p2d)
3185 {
3186         DSTACK(__FUNCTION_NAME);
3187
3188         MapSector *sector = NULL;
3189
3190         // The directory layout we're going to load from.
3191         //  1 - original sectors/xxxxzzzz/
3192         //  2 - new sectors2/xxx/zzz/
3193         //  If we load from anything but the latest structure, we will
3194         //  immediately save to the new one, and remove the old.
3195         int loadlayout = 1;
3196         std::string sectordir1 = getSectorDir(p2d, 1);
3197         std::string sectordir;
3198         if(fs::PathExists(sectordir1))
3199         {
3200                 sectordir = sectordir1;
3201         }
3202         else
3203         {
3204                 loadlayout = 2;
3205                 sectordir = getSectorDir(p2d, 2);
3206         }
3207
3208         try{
3209                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3210         }
3211         catch(InvalidFilenameException &e)
3212         {
3213                 return false;
3214         }
3215         catch(FileNotGoodException &e)
3216         {
3217                 return false;
3218         }
3219         catch(std::exception &e)
3220         {
3221                 return false;
3222         }
3223
3224         /*
3225                 Load blocks
3226         */
3227         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3228                         (sectordir);
3229         std::vector<fs::DirListNode>::iterator i2;
3230         for(i2=list2.begin(); i2!=list2.end(); i2++)
3231         {
3232                 // We want files
3233                 if(i2->dir)
3234                         continue;
3235                 try{
3236                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3237                 }
3238                 catch(InvalidFilenameException &e)
3239                 {
3240                         // This catches unknown crap in directory
3241                 }
3242         }
3243
3244         if(loadlayout != 2)
3245         {
3246                 infostream<<"Sector converted to new layout - deleting "<<
3247                         sectordir1<<std::endl;
3248                 fs::RecursiveDelete(sectordir1);
3249         }
3250
3251         return true;
3252 }
3253 #endif
3254
3255 void ServerMap::beginSave() {
3256         dbase->beginSave();
3257 }
3258
3259 void ServerMap::endSave() {
3260         dbase->endSave();
3261 }
3262
3263 void ServerMap::saveBlock(MapBlock *block)
3264 {
3265   dbase->saveBlock(block);
3266 }
3267
3268 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3269 {
3270         DSTACK(__FUNCTION_NAME);
3271
3272         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3273         try{
3274
3275                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3276                 if(is.good() == false)
3277                         throw FileNotGoodException("Cannot open block file");
3278
3279                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3280                 v2s16 p2d(p3d.X, p3d.Z);
3281
3282                 assert(sector->getPos() == p2d);
3283
3284                 u8 version = SER_FMT_VER_INVALID;
3285                 is.read((char*)&version, 1);
3286
3287                 if(is.fail())
3288                         throw SerializationError("ServerMap::loadBlock(): Failed"
3289                                         " to read MapBlock version");
3290
3291                 /*u32 block_size = MapBlock::serializedLength(version);
3292                 SharedBuffer<u8> data(block_size);
3293                 is.read((char*)*data, block_size);*/
3294
3295                 // This will always return a sector because we're the server
3296                 //MapSector *sector = emergeSector(p2d);
3297
3298                 MapBlock *block = NULL;
3299                 bool created_new = false;
3300                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3301                 if(block == NULL)
3302                 {
3303                         block = sector->createBlankBlockNoInsert(p3d.Y);
3304                         created_new = true;
3305                 }
3306
3307                 // Read basic data
3308                 block->deSerialize(is, version, true);
3309
3310                 // If it's a new block, insert it to the map
3311                 if(created_new)
3312                         sector->insertBlock(block);
3313
3314                 /*
3315                         Save blocks loaded in old format in new format
3316                 */
3317
3318                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3319                 {
3320                         saveBlock(block);
3321
3322                         // Should be in database now, so delete the old file
3323                         fs::RecursiveDelete(fullpath);
3324                 }
3325
3326                 // We just loaded it from the disk, so it's up-to-date.
3327                 block->resetModified();
3328
3329         }
3330         catch(SerializationError &e)
3331         {
3332                 infostream<<"WARNING: Invalid block data on disk "
3333                                 <<"fullpath="<<fullpath
3334                                 <<" (SerializationError). "
3335                                 <<"what()="<<e.what()
3336                                 <<std::endl;
3337                                 // Ignoring. A new one will be generated.
3338                 assert(0);
3339
3340                 // TODO: Backup file; name is in fullpath.
3341         }
3342 }
3343
3344 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3345 {
3346         DSTACK(__FUNCTION_NAME);
3347
3348         try {
3349                 std::istringstream is(*blob, std::ios_base::binary);
3350
3351                 u8 version = SER_FMT_VER_INVALID;
3352                 is.read((char*)&version, 1);
3353
3354                 if(is.fail())
3355                         throw SerializationError("ServerMap::loadBlock(): Failed"
3356                                         " to read MapBlock version");
3357
3358                 /*u32 block_size = MapBlock::serializedLength(version);
3359                 SharedBuffer<u8> data(block_size);
3360                 is.read((char*)*data, block_size);*/
3361
3362                 // This will always return a sector because we're the server
3363                 //MapSector *sector = emergeSector(p2d);
3364
3365                 MapBlock *block = NULL;
3366                 bool created_new = false;
3367                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3368                 if(block == NULL)
3369                 {
3370                         block = sector->createBlankBlockNoInsert(p3d.Y);
3371                         created_new = true;
3372                 }
3373
3374                 // Read basic data
3375                 block->deSerialize(is, version, true);
3376
3377                 // If it's a new block, insert it to the map
3378                 if(created_new)
3379                         sector->insertBlock(block);
3380
3381                 /*
3382                         Save blocks loaded in old format in new format
3383                 */
3384
3385                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3386                 // Only save if asked to; no need to update version
3387                 if(save_after_load)
3388                         saveBlock(block);
3389
3390                 // We just loaded it from, so it's up-to-date.
3391                 block->resetModified();
3392
3393         }
3394         catch(SerializationError &e)
3395         {
3396                 errorstream<<"Invalid block data in database"
3397                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3398                                 <<" (SerializationError): "<<e.what()<<std::endl;
3399
3400                 // TODO: Block should be marked as invalid in memory so that it is
3401                 // not touched but the game can run
3402
3403                 if(g_settings->getBool("ignore_world_load_errors")){
3404                         errorstream<<"Ignoring block load error. Duck and cover! "
3405                                         <<"(ignore_world_load_errors)"<<std::endl;
3406                 } else {
3407                         throw SerializationError("Invalid block data in database");
3408                         //assert(0);
3409                 }
3410         }
3411 }
3412
3413 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3414 {
3415         DSTACK(__FUNCTION_NAME);
3416
3417         v2s16 p2d(blockpos.X, blockpos.Z);
3418
3419         MapBlock *ret;
3420
3421         ret = dbase->loadBlock(blockpos);
3422         if (ret) return (ret);
3423         // Not found in database, try the files
3424
3425         // The directory layout we're going to load from.
3426         //  1 - original sectors/xxxxzzzz/
3427         //  2 - new sectors2/xxx/zzz/
3428         //  If we load from anything but the latest structure, we will
3429         //  immediately save to the new one, and remove the old.
3430         int loadlayout = 1;
3431         std::string sectordir1 = getSectorDir(p2d, 1);
3432         std::string sectordir;
3433         if(fs::PathExists(sectordir1))
3434         {
3435                 sectordir = sectordir1;
3436         }
3437         else
3438         {
3439                 loadlayout = 2;
3440                 sectordir = getSectorDir(p2d, 2);
3441         }
3442
3443         /*
3444                 Make sure sector is loaded
3445         */
3446         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3447         if(sector == NULL)
3448         {
3449                 try{
3450                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3451                 }
3452                 catch(InvalidFilenameException &e)
3453                 {
3454                         return NULL;
3455                 }
3456                 catch(FileNotGoodException &e)
3457                 {
3458                         return NULL;
3459                 }
3460                 catch(std::exception &e)
3461                 {
3462                         return NULL;
3463                 }
3464         }
3465
3466         /*
3467                 Make sure file exists
3468         */
3469
3470         std::string blockfilename = getBlockFilename(blockpos);
3471         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3472                 return NULL;
3473
3474         /*
3475                 Load block and save it to the database
3476         */
3477         loadBlock(sectordir, blockfilename, sector, true);
3478         return getBlockNoCreateNoEx(blockpos);
3479 }
3480
3481 void ServerMap::PrintInfo(std::ostream &out)
3482 {
3483         out<<"ServerMap: ";
3484 }
3485
3486 /*
3487         MapVoxelManipulator
3488 */
3489
3490 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3491 {
3492         m_map = map;
3493 }
3494
3495 MapVoxelManipulator::~MapVoxelManipulator()
3496 {
3497         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3498                         <<std::endl;*/
3499 }
3500
3501 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3502 {
3503         TimeTaker timer1("emerge", &emerge_time);
3504
3505         // Units of these are MapBlocks
3506         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3507         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3508
3509         VoxelArea block_area_nodes
3510                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3511
3512         addArea(block_area_nodes);
3513
3514         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3515         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3516         for(s32 x=p_min.X; x<=p_max.X; x++)
3517         {
3518                 u8 flags = 0;
3519                 MapBlock *block;
3520                 v3s16 p(x,y,z);
3521                 std::map<v3s16, u8>::iterator n;
3522                 n = m_loaded_blocks.find(p);
3523                 if(n != m_loaded_blocks.end())
3524                         continue;
3525
3526                 bool block_data_inexistent = false;
3527                 try
3528                 {
3529                         TimeTaker timer1("emerge load", &emerge_load_time);
3530
3531                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
3532                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3533                                         <<" wanted area: ";
3534                         a.print(infostream);
3535                         infostream<<std::endl;*/
3536
3537                         block = m_map->getBlockNoCreate(p);
3538                         if(block->isDummy())
3539                                 block_data_inexistent = true;
3540                         else
3541                                 block->copyTo(*this);
3542                 }
3543                 catch(InvalidPositionException &e)
3544                 {
3545                         block_data_inexistent = true;
3546                 }
3547
3548                 if(block_data_inexistent)
3549                 {
3550                         flags |= VMANIP_BLOCK_DATA_INEXIST;
3551
3552                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3553                         // Fill with VOXELFLAG_INEXISTENT
3554                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3555                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3556                         {
3557                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3558                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3559                         }
3560                 }
3561                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3562                 {
3563                         // Mark that block was loaded as blank
3564                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3565                 }*/
3566
3567                 m_loaded_blocks[p] = flags;
3568         }
3569
3570         //infostream<<"emerge done"<<std::endl;
3571 }
3572
3573 /*
3574         SUGG: Add an option to only update eg. water and air nodes.
3575               This will make it interfere less with important stuff if
3576                   run on background.
3577 */
3578 void MapVoxelManipulator::blitBack
3579                 (std::map<v3s16, MapBlock*> & modified_blocks)
3580 {
3581         if(m_area.getExtent() == v3s16(0,0,0))
3582                 return;
3583
3584         //TimeTaker timer1("blitBack");
3585
3586         /*infostream<<"blitBack(): m_loaded_blocks.size()="
3587                         <<m_loaded_blocks.size()<<std::endl;*/
3588
3589         /*
3590                 Initialize block cache
3591         */
3592         v3s16 blockpos_last;
3593         MapBlock *block = NULL;
3594         bool block_checked_in_modified = false;
3595
3596         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3597         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3598         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3599         {
3600                 v3s16 p(x,y,z);
3601
3602                 u8 f = m_flags[m_area.index(p)];
3603                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3604                         continue;
3605
3606                 MapNode &n = m_data[m_area.index(p)];
3607
3608                 v3s16 blockpos = getNodeBlockPos(p);
3609
3610                 try
3611                 {
3612                         // Get block
3613                         if(block == NULL || blockpos != blockpos_last){
3614                                 block = m_map->getBlockNoCreate(blockpos);
3615                                 blockpos_last = blockpos;
3616                                 block_checked_in_modified = false;
3617                         }
3618
3619                         // Calculate relative position in block
3620                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3621
3622                         // Don't continue if nothing has changed here
3623                         if(block->getNode(relpos) == n)
3624                                 continue;
3625
3626                         //m_map->setNode(m_area.MinEdge + p, n);
3627                         block->setNode(relpos, n);
3628
3629                         /*
3630                                 Make sure block is in modified_blocks
3631                         */
3632                         if(block_checked_in_modified == false)
3633                         {
3634                                 modified_blocks[blockpos] = block;
3635                                 block_checked_in_modified = true;
3636                         }
3637                 }
3638                 catch(InvalidPositionException &e)
3639                 {
3640                 }
3641         }
3642 }
3643
3644 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
3645                 MapVoxelManipulator(map),
3646                 m_create_area(false)
3647 {
3648 }
3649
3650 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
3651 {
3652 }
3653
3654 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3655 {
3656         // Just create the area so that it can be pointed to
3657         VoxelManipulator::emerge(a, caller_id);
3658 }
3659
3660 void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
3661                                                 v3s16 blockpos_max, bool load_if_inexistent)
3662 {
3663         TimeTaker timer1("initialEmerge", &emerge_time);
3664
3665         // Units of these are MapBlocks
3666         v3s16 p_min = blockpos_min;
3667         v3s16 p_max = blockpos_max;
3668
3669         VoxelArea block_area_nodes
3670                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3671
3672         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3673         if(size_MB >= 1)
3674         {
3675                 infostream<<"initialEmerge: area: ";
3676                 block_area_nodes.print(infostream);
3677                 infostream<<" ("<<size_MB<<"MB)";
3678                 infostream<<std::endl;
3679         }
3680
3681         addArea(block_area_nodes);
3682
3683         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3684         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3685         for(s32 x=p_min.X; x<=p_max.X; x++)
3686         {
3687                 u8 flags = 0;
3688                 MapBlock *block;
3689                 v3s16 p(x,y,z);
3690                 std::map<v3s16, u8>::iterator n;
3691                 n = m_loaded_blocks.find(p);
3692                 if(n != m_loaded_blocks.end())
3693                         continue;
3694
3695                 bool block_data_inexistent = false;
3696                 try
3697                 {
3698                         TimeTaker timer1("emerge load", &emerge_load_time);
3699
3700                         block = m_map->getBlockNoCreate(p);
3701                         if(block->isDummy())
3702                                 block_data_inexistent = true;
3703                         else
3704                                 block->copyTo(*this);
3705                 }
3706                 catch(InvalidPositionException &e)
3707                 {
3708                         block_data_inexistent = true;
3709                 }
3710
3711                 if(block_data_inexistent)
3712                 {
3713                         
3714                         if (load_if_inexistent) {
3715                                 ServerMap *svrmap = (ServerMap *)m_map;
3716                                 block = svrmap->emergeBlock(p, false);
3717                                 if (block == NULL)
3718                                         block = svrmap->createBlock(p);
3719                                 else
3720                                         block->copyTo(*this);
3721                         } else {
3722                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
3723                                 
3724                                 /*
3725                                         Mark area inexistent
3726                                 */
3727                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3728                                 // Fill with VOXELFLAG_INEXISTENT
3729                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3730                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3731                                 {
3732                                         s32 i = m_area.index(a.MinEdge.X,y,z);
3733                                         memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3734                                 }
3735                         }
3736                 }
3737                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3738                 {
3739                         // Mark that block was loaded as blank
3740                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3741                 }*/
3742
3743                 m_loaded_blocks[p] = flags;
3744         }
3745 }
3746
3747 void ManualMapVoxelManipulator::blitBackAll(
3748                 std::map<v3s16, MapBlock*> * modified_blocks)
3749 {
3750         if(m_area.getExtent() == v3s16(0,0,0))
3751                 return;
3752
3753         /*
3754                 Copy data of all blocks
3755         */
3756         for(std::map<v3s16, u8>::iterator
3757                         i = m_loaded_blocks.begin();
3758                         i != m_loaded_blocks.end(); ++i)
3759         {
3760                 v3s16 p = i->first;
3761                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3762                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
3763                 if(existed == false)
3764                 {
3765                         continue;
3766                 }
3767
3768                 block->copyFrom(*this);
3769
3770                 if(modified_blocks)
3771                         (*modified_blocks)[p] = block;
3772         }
3773 }
3774
3775 //END