Remove emerge and speedup addArea by using memcopy instead of one by one assignment
[oweals/minetest.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 void 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                         MapBlock * block = getBlockNoCreateNoEx(p);
2373                         if (block != NULL)
2374                                 block->setLightingExpired(false);
2375                 }
2376
2377 #if 0
2378                 if(enable_mapgen_debug_info == false)
2379                         t.stop(true); // Hide output
2380 #endif
2381         }
2382
2383         /*
2384                 Go through changed blocks
2385         */
2386         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2387                         i != changed_blocks.end(); ++i)
2388         {
2389                 MapBlock *block = i->second;
2390                 if (!block)
2391                         continue;
2392                 /*
2393                         Update day/night difference cache of the MapBlocks
2394                 */
2395                 block->expireDayNightDiff();
2396                 /*
2397                         Set block as modified
2398                 */
2399                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2400                                 "finishBlockMake expireDayNightDiff");
2401         }
2402
2403         /*
2404                 Set central blocks as generated
2405         */
2406         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2407         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2408         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2409         {
2410                 v3s16 p(x, y, z);
2411                 MapBlock *block = getBlockNoCreateNoEx(p);
2412                 if (!block)
2413                         continue;
2414                 block->setGenerated(true);
2415         }
2416
2417         /*
2418                 Save changed parts of map
2419                 NOTE: Will be saved later.
2420         */
2421         //save(MOD_STATE_WRITE_AT_UNLOAD);
2422
2423         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2424                         <<","<<blockpos_requested.Y<<","
2425                         <<blockpos_requested.Z<<")"<<std::endl;*/
2426
2427
2428 #if 0
2429         if(enable_mapgen_debug_info)
2430         {
2431                 /*
2432                         Analyze resulting blocks
2433                 */
2434                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2435                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2436                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2437                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2438                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2439                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2440                 {
2441                         v3s16 p = v3s16(x,y,z);
2442                         MapBlock *block = getBlockNoCreateNoEx(p);
2443                         char spos[20];
2444                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2445                         infostream<<"Generated "<<spos<<": "
2446                                         <<analyze_block(block)<<std::endl;
2447                 }
2448         }
2449 #endif
2450
2451         getBlockNoCreateNoEx(blockpos_requested);
2452 }
2453
2454 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2455 {
2456         DSTACKF("%s: p2d=(%d,%d)",
2457                         __FUNCTION_NAME,
2458                         p2d.X, p2d.Y);
2459
2460         /*
2461                 Check if it exists already in memory
2462         */
2463         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2464         if(sector != NULL)
2465                 return sector;
2466
2467         /*
2468                 Try to load it from disk (with blocks)
2469         */
2470         //if(loadSectorFull(p2d) == true)
2471
2472         /*
2473                 Try to load metadata from disk
2474         */
2475 #if 0
2476         if(loadSectorMeta(p2d) == true)
2477         {
2478                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2479                 if(sector == NULL)
2480                 {
2481                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2482                         throw InvalidPositionException("");
2483                 }
2484                 return sector;
2485         }
2486 #endif
2487         /*
2488                 Do not create over-limit
2489         */
2490         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2491         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2492         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2493         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2494                 throw InvalidPositionException("createSector(): pos. over limit");
2495
2496         /*
2497                 Generate blank sector
2498         */
2499
2500         sector = new ServerMapSector(this, p2d, m_gamedef);
2501
2502         // Sector position on map in nodes
2503         //v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2504
2505         /*
2506                 Insert to container
2507         */
2508         m_sectors[p2d] = sector;
2509
2510         return sector;
2511 }
2512
2513 #if 0
2514 /*
2515         This is a quick-hand function for calling makeBlock().
2516 */
2517 MapBlock * ServerMap::generateBlock(
2518                 v3s16 p,
2519                 std::map<v3s16, MapBlock*> &modified_blocks
2520 )
2521 {
2522         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2523
2524         /*infostream<<"generateBlock(): "
2525                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2526                         <<std::endl;*/
2527
2528         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2529
2530         TimeTaker timer("generateBlock");
2531
2532         //MapBlock *block = original_dummy;
2533
2534         v2s16 p2d(p.X, p.Z);
2535         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2536
2537         /*
2538                 Do not generate over-limit
2539         */
2540         if(blockpos_over_limit(p))
2541         {
2542                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2543                 throw InvalidPositionException("generateBlock(): pos. over limit");
2544         }
2545
2546         /*
2547                 Create block make data
2548         */
2549         BlockMakeData data;
2550         initBlockMake(&data, p);
2551
2552         /*
2553                 Generate block
2554         */
2555         {
2556                 TimeTaker t("mapgen::make_block()");
2557                 mapgen->makeChunk(&data);
2558                 //mapgen::make_block(&data);
2559
2560                 if(enable_mapgen_debug_info == false)
2561                         t.stop(true); // Hide output
2562         }
2563
2564         /*
2565                 Blit data back on map, update lighting, add mobs and whatever this does
2566         */
2567         finishBlockMake(&data, modified_blocks);
2568
2569         /*
2570                 Get central block
2571         */
2572         MapBlock *block = getBlockNoCreateNoEx(p);
2573
2574 #if 0
2575         /*
2576                 Check result
2577         */
2578         if(block)
2579         {
2580                 bool erroneus_content = false;
2581                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2582                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2583                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2584                 {
2585                         v3s16 p(x0,y0,z0);
2586                         MapNode n = block->getNode(p);
2587                         if(n.getContent() == CONTENT_IGNORE)
2588                         {
2589                                 infostream<<"CONTENT_IGNORE at "
2590                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2591                                                 <<std::endl;
2592                                 erroneus_content = true;
2593                                 assert(0);
2594                         }
2595                 }
2596                 if(erroneus_content)
2597                 {
2598                         assert(0);
2599                 }
2600         }
2601 #endif
2602
2603 #if 0
2604         /*
2605                 Generate a completely empty block
2606         */
2607         if(block)
2608         {
2609                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2610                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2611                 {
2612                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2613                         {
2614                                 MapNode n;
2615                                 n.setContent(CONTENT_AIR);
2616                                 block->setNode(v3s16(x0,y0,z0), n);
2617                         }
2618                 }
2619         }
2620 #endif
2621
2622         if(enable_mapgen_debug_info == false)
2623                 timer.stop(true); // Hide output
2624
2625         return block;
2626 }
2627 #endif
2628
2629 MapBlock * ServerMap::createBlock(v3s16 p)
2630 {
2631         DSTACKF("%s: p=(%d,%d,%d)",
2632                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2633
2634         /*
2635                 Do not create over-limit
2636         */
2637         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2638         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2639         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2640         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2641         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2642         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2643                 throw InvalidPositionException("createBlock(): pos. over limit");
2644
2645         v2s16 p2d(p.X, p.Z);
2646         s16 block_y = p.Y;
2647         /*
2648                 This will create or load a sector if not found in memory.
2649                 If block exists on disk, it will be loaded.
2650
2651                 NOTE: On old save formats, this will be slow, as it generates
2652                       lighting on blocks for them.
2653         */
2654         ServerMapSector *sector;
2655         try{
2656                 sector = (ServerMapSector*)createSector(p2d);
2657                 assert(sector->getId() == MAPSECTOR_SERVER);
2658         }
2659         catch(InvalidPositionException &e)
2660         {
2661                 infostream<<"createBlock: createSector() failed"<<std::endl;
2662                 throw e;
2663         }
2664         /*
2665                 NOTE: This should not be done, or at least the exception
2666                 should not be passed on as std::exception, because it
2667                 won't be catched at all.
2668         */
2669         /*catch(std::exception &e)
2670         {
2671                 infostream<<"createBlock: createSector() failed: "
2672                                 <<e.what()<<std::endl;
2673                 throw e;
2674         }*/
2675
2676         /*
2677                 Try to get a block from the sector
2678         */
2679
2680         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2681         if(block)
2682         {
2683                 if(block->isDummy())
2684                         block->unDummify();
2685                 return block;
2686         }
2687         // Create blank
2688         block = sector->createBlankBlock(block_y);
2689
2690         return block;
2691 }
2692
2693 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2694 {
2695         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2696                         __FUNCTION_NAME,
2697                         p.X, p.Y, p.Z, create_blank);
2698
2699         {
2700                 MapBlock *block = getBlockNoCreateNoEx(p);
2701                 if(block && block->isDummy() == false)
2702                         return block;
2703         }
2704
2705         {
2706                 MapBlock *block = loadBlock(p);
2707                 if(block)
2708                         return block;
2709         }
2710
2711         if (create_blank) {
2712                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2713                 MapBlock *block = sector->createBlankBlock(p.Y);
2714
2715                 return block;
2716         }
2717
2718 #if 0
2719         if(allow_generate)
2720         {
2721                 std::map<v3s16, MapBlock*> modified_blocks;
2722                 MapBlock *block = generateBlock(p, modified_blocks);
2723                 if(block)
2724                 {
2725                         MapEditEvent event;
2726                         event.type = MEET_OTHER;
2727                         event.p = p;
2728
2729                         // Copy modified_blocks to event
2730                         for(std::map<v3s16, MapBlock*>::iterator
2731                                         i = modified_blocks.begin();
2732                                         i != modified_blocks.end(); ++i)
2733                         {
2734                                 event.modified_blocks.insert(i->first);
2735                         }
2736
2737                         // Queue event
2738                         dispatchEvent(&event);
2739
2740                         return block;
2741                 }
2742         }
2743 #endif
2744
2745         return NULL;
2746 }
2747
2748 MapBlock *ServerMap::getBlockOrEmerge(v3s16 p3d)
2749 {
2750         MapBlock *block = getBlockNoCreateNoEx(p3d);
2751         if (block == NULL)
2752                 m_emerge->enqueueBlockEmerge(PEER_ID_INEXISTENT, p3d, false);
2753
2754         return block;
2755 }
2756
2757 void ServerMap::prepareBlock(MapBlock *block) {
2758 }
2759
2760 s16 ServerMap::findGroundLevel(v2s16 p2d)
2761 {
2762 #if 0
2763         /*
2764                 Uh, just do something random...
2765         */
2766         // Find existing map from top to down
2767         s16 max=63;
2768         s16 min=-64;
2769         v3s16 p(p2d.X, max, p2d.Y);
2770         for(; p.Y>min; p.Y--)
2771         {
2772                 MapNode n = getNodeNoEx(p);
2773                 if(n.getContent() != CONTENT_IGNORE)
2774                         break;
2775         }
2776         if(p.Y == min)
2777                 goto plan_b;
2778         // If this node is not air, go to plan b
2779         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2780                 goto plan_b;
2781         // Search existing walkable and return it
2782         for(; p.Y>min; p.Y--)
2783         {
2784                 MapNode n = getNodeNoEx(p);
2785                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2786                         return p.Y;
2787         }
2788
2789         // Move to plan b
2790 plan_b:
2791 #endif
2792
2793         /*
2794                 Determine from map generator noise functions
2795         */
2796
2797         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2798         return level;
2799
2800         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2801         //return (s16)level;
2802 }
2803
2804 bool ServerMap::loadFromFolders() {
2805         if(!dbase->Initialized() && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite")) // ?
2806                 return true;
2807         return false;
2808 }
2809
2810 void ServerMap::createDirs(std::string path)
2811 {
2812         if(fs::CreateAllDirs(path) == false)
2813         {
2814                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2815                                 <<"\""<<path<<"\""<<std::endl;
2816                 throw BaseException("ServerMap failed to create directory");
2817         }
2818 }
2819
2820 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2821 {
2822         char cc[9];
2823         switch(layout)
2824         {
2825                 case 1:
2826                         snprintf(cc, 9, "%.4x%.4x",
2827                                 (unsigned int)pos.X&0xffff,
2828                                 (unsigned int)pos.Y&0xffff);
2829
2830                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2831                 case 2:
2832                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2833                                 (unsigned int)pos.X&0xfff,
2834                                 (unsigned int)pos.Y&0xfff);
2835
2836                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2837                 default:
2838                         assert(false);
2839                         return "";
2840         }
2841 }
2842
2843 v2s16 ServerMap::getSectorPos(std::string dirname)
2844 {
2845         unsigned int x = 0, y = 0;
2846         int r;
2847         std::string component;
2848         fs::RemoveLastPathComponent(dirname, &component, 1);
2849         if(component.size() == 8)
2850         {
2851                 // Old layout
2852                 r = sscanf(component.c_str(), "%4x%4x", &x, &y);
2853         }
2854         else if(component.size() == 3)
2855         {
2856                 // New layout
2857                 fs::RemoveLastPathComponent(dirname, &component, 2);
2858                 r = sscanf(component.c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2859                 // Sign-extend the 12 bit values up to 16 bits...
2860                 if(x&0x800) x|=0xF000;
2861                 if(y&0x800) y|=0xF000;
2862         }
2863         else
2864         {
2865                 assert(false);
2866         }
2867         assert(r == 2);
2868         v2s16 pos((s16)x, (s16)y);
2869         return pos;
2870 }
2871
2872 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2873 {
2874         v2s16 p2d = getSectorPos(sectordir);
2875
2876         if(blockfile.size() != 4){
2877                 throw InvalidFilenameException("Invalid block filename");
2878         }
2879         unsigned int y;
2880         int r = sscanf(blockfile.c_str(), "%4x", &y);
2881         if(r != 1)
2882                 throw InvalidFilenameException("Invalid block filename");
2883         return v3s16(p2d.X, y, p2d.Y);
2884 }
2885
2886 std::string ServerMap::getBlockFilename(v3s16 p)
2887 {
2888         char cc[5];
2889         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2890         return cc;
2891 }
2892
2893 void ServerMap::save(ModifiedState save_level)
2894 {
2895         DSTACK(__FUNCTION_NAME);
2896         if(m_map_saving_enabled == false)
2897         {
2898                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2899                 return;
2900         }
2901
2902         if(save_level == MOD_STATE_CLEAN)
2903                 infostream<<"ServerMap: Saving whole map, this can take time."
2904                                 <<std::endl;
2905
2906         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
2907         {
2908                 saveMapMeta();
2909         }
2910
2911         // Profile modified reasons
2912         Profiler modprofiler;
2913
2914         u32 sector_meta_count = 0;
2915         u32 block_count = 0;
2916         u32 block_count_all = 0; // Number of blocks in memory
2917
2918         // Don't do anything with sqlite unless something is really saved
2919         bool save_started = false;
2920
2921         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
2922                 i != m_sectors.end(); ++i)
2923         {
2924                 ServerMapSector *sector = (ServerMapSector*)i->second;
2925                 assert(sector->getId() == MAPSECTOR_SERVER);
2926
2927                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
2928                 {
2929                         saveSectorMeta(sector);
2930                         sector_meta_count++;
2931                 }
2932                 std::list<MapBlock*> blocks;
2933                 sector->getBlocks(blocks);
2934
2935                 for(std::list<MapBlock*>::iterator j = blocks.begin();
2936                         j != blocks.end(); ++j)
2937                 {
2938                         MapBlock *block = *j;
2939
2940                         block_count_all++;
2941
2942                         if(block->getModified() >= (u32)save_level)
2943                         {
2944                                 // Lazy beginSave()
2945                                 if(!save_started){
2946                                         beginSave();
2947                                         save_started = true;
2948                                 }
2949
2950                                 modprofiler.add(block->getModifiedReason(), 1);
2951
2952                                 saveBlock(block);
2953                                 block_count++;
2954
2955                                 /*infostream<<"ServerMap: Written block ("
2956                                                 <<block->getPos().X<<","
2957                                                 <<block->getPos().Y<<","
2958                                                 <<block->getPos().Z<<")"
2959                                                 <<std::endl;*/
2960                         }
2961                 }
2962         }
2963         if(save_started)
2964                 endSave();
2965
2966         /*
2967                 Only print if something happened or saved whole map
2968         */
2969         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
2970                         || block_count != 0)
2971         {
2972                 infostream<<"ServerMap: Written: "
2973                                 <<sector_meta_count<<" sector metadata files, "
2974                                 <<block_count<<" block files"
2975                                 <<", "<<block_count_all<<" blocks in memory."
2976                                 <<std::endl;
2977                 PrintInfo(infostream); // ServerMap/ClientMap:
2978                 infostream<<"Blocks modified by: "<<std::endl;
2979                 modprofiler.print(infostream);
2980         }
2981 }
2982
2983 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
2984 {
2985         if(loadFromFolders()){
2986                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
2987                                 <<"all blocks that are stored in flat files"<<std::endl;
2988         }
2989         dbase->listAllLoadableBlocks(dst);
2990 }
2991
2992 void ServerMap::listAllLoadedBlocks(std::list<v3s16> &dst)
2993 {
2994         for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
2995                 si != m_sectors.end(); ++si)
2996         {
2997                 MapSector *sector = si->second;
2998
2999                 std::list<MapBlock*> blocks;
3000                 sector->getBlocks(blocks);
3001
3002                 for(std::list<MapBlock*>::iterator i = blocks.begin();
3003                                 i != blocks.end(); ++i)
3004                 {
3005                         MapBlock *block = (*i);
3006                         v3s16 p = block->getPos();
3007                         dst.push_back(p);
3008                 }
3009         }
3010 }
3011
3012 void ServerMap::saveMapMeta()
3013 {
3014         DSTACK(__FUNCTION_NAME);
3015
3016         /*infostream<<"ServerMap::saveMapMeta(): "
3017                         <<"seed="<<m_seed
3018                         <<std::endl;*/
3019
3020         createDirs(m_savedir);
3021
3022         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3023         std::ostringstream ss(std::ios_base::binary);
3024
3025         Settings params;
3026
3027         m_emerge->saveParamsToSettings(&params);
3028         params.writeLines(ss);
3029
3030         ss<<"[end_of_params]\n";
3031
3032         if(!fs::safeWriteToFile(fullpath, ss.str()))
3033         {
3034                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3035                                 <<"could not write "<<fullpath<<std::endl;
3036                 throw FileNotGoodException("Cannot save chunk metadata");
3037         }
3038
3039         m_map_metadata_changed = false;
3040 }
3041
3042 void ServerMap::loadMapMeta()
3043 {
3044         DSTACK(__FUNCTION_NAME);
3045
3046         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3047                         <<std::endl;*/
3048
3049         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3050         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3051         if(is.good() == false)
3052         {
3053                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3054                                 <<"could not open"<<fullpath<<std::endl;
3055                 throw FileNotGoodException("Cannot open map metadata");
3056         }
3057
3058         Settings params;
3059
3060         for(;;)
3061         {
3062                 if(is.eof())
3063                         throw SerializationError
3064                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3065                 std::string line;
3066                 std::getline(is, line);
3067                 std::string trimmedline = trim(line);
3068                 if(trimmedline == "[end_of_params]")
3069                         break;
3070                 params.parseConfigLine(line);
3071         }
3072
3073         m_emerge->loadParamsFromSettings(&params);
3074
3075         verbosestream<<"ServerMap::loadMapMeta(): seed="
3076                 << m_emerge->params.seed<<std::endl;
3077 }
3078
3079 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3080 {
3081         DSTACK(__FUNCTION_NAME);
3082         // Format used for writing
3083         u8 version = SER_FMT_VER_HIGHEST_WRITE;
3084         // Get destination
3085         v2s16 pos = sector->getPos();
3086         std::string dir = getSectorDir(pos);
3087         createDirs(dir);
3088
3089         std::string fullpath = dir + DIR_DELIM + "meta";
3090         std::ostringstream ss(std::ios_base::binary);
3091
3092         sector->serialize(ss, version);
3093
3094         if(!fs::safeWriteToFile(fullpath, ss.str()))
3095                 throw FileNotGoodException("Cannot write sector metafile");
3096
3097         sector->differs_from_disk = false;
3098 }
3099
3100 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3101 {
3102         DSTACK(__FUNCTION_NAME);
3103         // Get destination
3104         v2s16 p2d = getSectorPos(sectordir);
3105
3106         ServerMapSector *sector = NULL;
3107
3108         std::string fullpath = sectordir + DIR_DELIM + "meta";
3109         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3110         if(is.good() == false)
3111         {
3112                 // If the directory exists anyway, it probably is in some old
3113                 // format. Just go ahead and create the sector.
3114                 if(fs::PathExists(sectordir))
3115                 {
3116                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3117                                         <<fullpath<<" doesn't exist but directory does."
3118                                         <<" Continuing with a sector with no metadata."
3119                                         <<std::endl;*/
3120                         sector = new ServerMapSector(this, p2d, m_gamedef);
3121                         m_sectors[p2d] = sector;
3122                 }
3123                 else
3124                 {
3125                         throw FileNotGoodException("Cannot open sector metafile");
3126                 }
3127         }
3128         else
3129         {
3130                 sector = ServerMapSector::deSerialize
3131                                 (is, this, p2d, m_sectors, m_gamedef);
3132                 if(save_after_load)
3133                         saveSectorMeta(sector);
3134         }
3135
3136         sector->differs_from_disk = false;
3137
3138         return sector;
3139 }
3140
3141 bool ServerMap::loadSectorMeta(v2s16 p2d)
3142 {
3143         DSTACK(__FUNCTION_NAME);
3144
3145         MapSector *sector = NULL;
3146
3147         // The directory layout we're going to load from.
3148         //  1 - original sectors/xxxxzzzz/
3149         //  2 - new sectors2/xxx/zzz/
3150         //  If we load from anything but the latest structure, we will
3151         //  immediately save to the new one, and remove the old.
3152         int loadlayout = 1;
3153         std::string sectordir1 = getSectorDir(p2d, 1);
3154         std::string sectordir;
3155         if(fs::PathExists(sectordir1))
3156         {
3157                 sectordir = sectordir1;
3158         }
3159         else
3160         {
3161                 loadlayout = 2;
3162                 sectordir = getSectorDir(p2d, 2);
3163         }
3164
3165         try{
3166                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3167         }
3168         catch(InvalidFilenameException &e)
3169         {
3170                 return false;
3171         }
3172         catch(FileNotGoodException &e)
3173         {
3174                 return false;
3175         }
3176         catch(std::exception &e)
3177         {
3178                 return false;
3179         }
3180
3181         return true;
3182 }
3183
3184 #if 0
3185 bool ServerMap::loadSectorFull(v2s16 p2d)
3186 {
3187         DSTACK(__FUNCTION_NAME);
3188
3189         MapSector *sector = NULL;
3190
3191         // The directory layout we're going to load from.
3192         //  1 - original sectors/xxxxzzzz/
3193         //  2 - new sectors2/xxx/zzz/
3194         //  If we load from anything but the latest structure, we will
3195         //  immediately save to the new one, and remove the old.
3196         int loadlayout = 1;
3197         std::string sectordir1 = getSectorDir(p2d, 1);
3198         std::string sectordir;
3199         if(fs::PathExists(sectordir1))
3200         {
3201                 sectordir = sectordir1;
3202         }
3203         else
3204         {
3205                 loadlayout = 2;
3206                 sectordir = getSectorDir(p2d, 2);
3207         }
3208
3209         try{
3210                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3211         }
3212         catch(InvalidFilenameException &e)
3213         {
3214                 return false;
3215         }
3216         catch(FileNotGoodException &e)
3217         {
3218                 return false;
3219         }
3220         catch(std::exception &e)
3221         {
3222                 return false;
3223         }
3224
3225         /*
3226                 Load blocks
3227         */
3228         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3229                         (sectordir);
3230         std::vector<fs::DirListNode>::iterator i2;
3231         for(i2=list2.begin(); i2!=list2.end(); i2++)
3232         {
3233                 // We want files
3234                 if(i2->dir)
3235                         continue;
3236                 try{
3237                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3238                 }
3239                 catch(InvalidFilenameException &e)
3240                 {
3241                         // This catches unknown crap in directory
3242                 }
3243         }
3244
3245         if(loadlayout != 2)
3246         {
3247                 infostream<<"Sector converted to new layout - deleting "<<
3248                         sectordir1<<std::endl;
3249                 fs::RecursiveDelete(sectordir1);
3250         }
3251
3252         return true;
3253 }
3254 #endif
3255
3256 void ServerMap::beginSave() {
3257         dbase->beginSave();
3258 }
3259
3260 void ServerMap::endSave() {
3261         dbase->endSave();
3262 }
3263
3264 void ServerMap::saveBlock(MapBlock *block)
3265 {
3266   dbase->saveBlock(block);
3267 }
3268
3269 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3270 {
3271         DSTACK(__FUNCTION_NAME);
3272
3273         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3274         try{
3275
3276                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3277                 if(is.good() == false)
3278                         throw FileNotGoodException("Cannot open block file");
3279
3280                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3281                 v2s16 p2d(p3d.X, p3d.Z);
3282
3283                 assert(sector->getPos() == p2d);
3284
3285                 u8 version = SER_FMT_VER_INVALID;
3286                 is.read((char*)&version, 1);
3287
3288                 if(is.fail())
3289                         throw SerializationError("ServerMap::loadBlock(): Failed"
3290                                         " to read MapBlock version");
3291
3292                 /*u32 block_size = MapBlock::serializedLength(version);
3293                 SharedBuffer<u8> data(block_size);
3294                 is.read((char*)*data, block_size);*/
3295
3296                 // This will always return a sector because we're the server
3297                 //MapSector *sector = emergeSector(p2d);
3298
3299                 MapBlock *block = NULL;
3300                 bool created_new = false;
3301                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3302                 if(block == NULL)
3303                 {
3304                         block = sector->createBlankBlockNoInsert(p3d.Y);
3305                         created_new = true;
3306                 }
3307
3308                 // Read basic data
3309                 block->deSerialize(is, version, true);
3310
3311                 // If it's a new block, insert it to the map
3312                 if(created_new)
3313                         sector->insertBlock(block);
3314
3315                 /*
3316                         Save blocks loaded in old format in new format
3317                 */
3318
3319                 if(version < SER_FMT_VER_HIGHEST_WRITE || save_after_load)
3320                 {
3321                         saveBlock(block);
3322
3323                         // Should be in database now, so delete the old file
3324                         fs::RecursiveDelete(fullpath);
3325                 }
3326
3327                 // We just loaded it from the disk, so it's up-to-date.
3328                 block->resetModified();
3329
3330         }
3331         catch(SerializationError &e)
3332         {
3333                 infostream<<"WARNING: Invalid block data on disk "
3334                                 <<"fullpath="<<fullpath
3335                                 <<" (SerializationError). "
3336                                 <<"what()="<<e.what()
3337                                 <<std::endl;
3338                                 // Ignoring. A new one will be generated.
3339                 assert(0);
3340
3341                 // TODO: Backup file; name is in fullpath.
3342         }
3343 }
3344
3345 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3346 {
3347         DSTACK(__FUNCTION_NAME);
3348
3349         try {
3350                 std::istringstream is(*blob, std::ios_base::binary);
3351
3352                 u8 version = SER_FMT_VER_INVALID;
3353                 is.read((char*)&version, 1);
3354
3355                 if(is.fail())
3356                         throw SerializationError("ServerMap::loadBlock(): Failed"
3357                                         " to read MapBlock version");
3358
3359                 /*u32 block_size = MapBlock::serializedLength(version);
3360                 SharedBuffer<u8> data(block_size);
3361                 is.read((char*)*data, block_size);*/
3362
3363                 // This will always return a sector because we're the server
3364                 //MapSector *sector = emergeSector(p2d);
3365
3366                 MapBlock *block = NULL;
3367                 bool created_new = false;
3368                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3369                 if(block == NULL)
3370                 {
3371                         block = sector->createBlankBlockNoInsert(p3d.Y);
3372                         created_new = true;
3373                 }
3374
3375                 // Read basic data
3376                 block->deSerialize(is, version, true);
3377
3378                 // If it's a new block, insert it to the map
3379                 if(created_new)
3380                         sector->insertBlock(block);
3381
3382                 /*
3383                         Save blocks loaded in old format in new format
3384                 */
3385
3386                 //if(version < SER_FMT_VER_HIGHEST_READ || save_after_load)
3387                 // Only save if asked to; no need to update version
3388                 if(save_after_load)
3389                         saveBlock(block);
3390
3391                 // We just loaded it from, so it's up-to-date.
3392                 block->resetModified();
3393
3394         }
3395         catch(SerializationError &e)
3396         {
3397                 errorstream<<"Invalid block data in database"
3398                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3399                                 <<" (SerializationError): "<<e.what()<<std::endl;
3400
3401                 // TODO: Block should be marked as invalid in memory so that it is
3402                 // not touched but the game can run
3403
3404                 if(g_settings->getBool("ignore_world_load_errors")){
3405                         errorstream<<"Ignoring block load error. Duck and cover! "
3406                                         <<"(ignore_world_load_errors)"<<std::endl;
3407                 } else {
3408                         throw SerializationError("Invalid block data in database");
3409                         //assert(0);
3410                 }
3411         }
3412 }
3413
3414 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3415 {
3416         DSTACK(__FUNCTION_NAME);
3417
3418         v2s16 p2d(blockpos.X, blockpos.Z);
3419
3420         MapBlock *ret;
3421
3422         ret = dbase->loadBlock(blockpos);
3423         if (ret) return (ret);
3424         // Not found in database, try the files
3425
3426         // The directory layout we're going to load from.
3427         //  1 - original sectors/xxxxzzzz/
3428         //  2 - new sectors2/xxx/zzz/
3429         //  If we load from anything but the latest structure, we will
3430         //  immediately save to the new one, and remove the old.
3431         int loadlayout = 1;
3432         std::string sectordir1 = getSectorDir(p2d, 1);
3433         std::string sectordir;
3434         if(fs::PathExists(sectordir1))
3435         {
3436                 sectordir = sectordir1;
3437         }
3438         else
3439         {
3440                 loadlayout = 2;
3441                 sectordir = getSectorDir(p2d, 2);
3442         }
3443
3444         /*
3445                 Make sure sector is loaded
3446         */
3447         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3448         if(sector == NULL)
3449         {
3450                 try{
3451                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3452                 }
3453                 catch(InvalidFilenameException &e)
3454                 {
3455                         return NULL;
3456                 }
3457                 catch(FileNotGoodException &e)
3458                 {
3459                         return NULL;
3460                 }
3461                 catch(std::exception &e)
3462                 {
3463                         return NULL;
3464                 }
3465         }
3466
3467         /*
3468                 Make sure file exists
3469         */
3470
3471         std::string blockfilename = getBlockFilename(blockpos);
3472         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3473                 return NULL;
3474
3475         /*
3476                 Load block and save it to the database
3477         */
3478         loadBlock(sectordir, blockfilename, sector, true);
3479         return getBlockNoCreateNoEx(blockpos);
3480 }
3481
3482 void ServerMap::PrintInfo(std::ostream &out)
3483 {
3484         out<<"ServerMap: ";
3485 }
3486
3487 /*
3488         MapVoxelManipulator
3489 */
3490
3491 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3492 {
3493         m_map = map;
3494 }
3495
3496 MapVoxelManipulator::~MapVoxelManipulator()
3497 {
3498         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3499                         <<std::endl;*/
3500 }
3501
3502 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3503 {
3504         TimeTaker timer1("emerge", &emerge_time);
3505
3506         // Units of these are MapBlocks
3507         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3508         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3509
3510         VoxelArea block_area_nodes
3511                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3512
3513         addArea(block_area_nodes);
3514
3515         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3516         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3517         for(s32 x=p_min.X; x<=p_max.X; x++)
3518         {
3519                 u8 flags = 0;
3520                 MapBlock *block;
3521                 v3s16 p(x,y,z);
3522                 std::map<v3s16, u8>::iterator n;
3523                 n = m_loaded_blocks.find(p);
3524                 if(n != m_loaded_blocks.end())
3525                         continue;
3526
3527                 bool block_data_inexistent = false;
3528                 try
3529                 {
3530                         TimeTaker timer1("emerge load", &emerge_load_time);
3531
3532                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
3533                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3534                                         <<" wanted area: ";
3535                         a.print(infostream);
3536                         infostream<<std::endl;*/
3537
3538                         block = m_map->getBlockNoCreate(p);
3539                         if(block->isDummy())
3540                                 block_data_inexistent = true;
3541                         else
3542                                 block->copyTo(*this);
3543                 }
3544                 catch(InvalidPositionException &e)
3545                 {
3546                         block_data_inexistent = true;
3547                 }
3548
3549                 if(block_data_inexistent)
3550                 {
3551                         flags |= VMANIP_BLOCK_DATA_INEXIST;
3552
3553                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3554                         // Fill with VOXELFLAG_NO_DATA
3555                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3556                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3557                         {
3558                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3559                                 memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
3560                         }
3561                 }
3562                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3563                 {
3564                         // Mark that block was loaded as blank
3565                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3566                 }*/
3567
3568                 m_loaded_blocks[p] = flags;
3569         }
3570
3571         //infostream<<"emerge done"<<std::endl;
3572 }
3573
3574 /*
3575         SUGG: Add an option to only update eg. water and air nodes.
3576               This will make it interfere less with important stuff if
3577                   run on background.
3578 */
3579 void MapVoxelManipulator::blitBack
3580                 (std::map<v3s16, MapBlock*> & modified_blocks)
3581 {
3582         if(m_area.getExtent() == v3s16(0,0,0))
3583                 return;
3584
3585         //TimeTaker timer1("blitBack");
3586
3587         /*infostream<<"blitBack(): m_loaded_blocks.size()="
3588                         <<m_loaded_blocks.size()<<std::endl;*/
3589
3590         /*
3591                 Initialize block cache
3592         */
3593         v3s16 blockpos_last;
3594         MapBlock *block = NULL;
3595         bool block_checked_in_modified = false;
3596
3597         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3598         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3599         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3600         {
3601                 v3s16 p(x,y,z);
3602
3603                 u8 f = m_flags[m_area.index(p)];
3604                 if(f & (VOXELFLAG_NO_DATA))
3605                         continue;
3606
3607                 MapNode &n = m_data[m_area.index(p)];
3608
3609                 v3s16 blockpos = getNodeBlockPos(p);
3610
3611                 try
3612                 {
3613                         // Get block
3614                         if(block == NULL || blockpos != blockpos_last){
3615                                 block = m_map->getBlockNoCreate(blockpos);
3616                                 blockpos_last = blockpos;
3617                                 block_checked_in_modified = false;
3618                         }
3619
3620                         // Calculate relative position in block
3621                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3622
3623                         // Don't continue if nothing has changed here
3624                         if(block->getNode(relpos) == n)
3625                                 continue;
3626
3627                         //m_map->setNode(m_area.MinEdge + p, n);
3628                         block->setNode(relpos, n);
3629
3630                         /*
3631                                 Make sure block is in modified_blocks
3632                         */
3633                         if(block_checked_in_modified == false)
3634                         {
3635                                 modified_blocks[blockpos] = block;
3636                                 block_checked_in_modified = true;
3637                         }
3638                 }
3639                 catch(InvalidPositionException &e)
3640                 {
3641                 }
3642         }
3643 }
3644
3645 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
3646                 MapVoxelManipulator(map),
3647                 m_create_area(false)
3648 {
3649 }
3650
3651 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
3652 {
3653 }
3654
3655 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3656 {
3657         // Just create the area so that it can be pointed to
3658         VoxelManipulator::addArea(a);
3659 }
3660
3661 void ManualMapVoxelManipulator::initialEmerge(v3s16 blockpos_min,
3662                                                 v3s16 blockpos_max, bool load_if_inexistent)
3663 {
3664         TimeTaker timer1("initialEmerge", &emerge_time);
3665
3666         // Units of these are MapBlocks
3667         v3s16 p_min = blockpos_min;
3668         v3s16 p_max = blockpos_max;
3669
3670         VoxelArea block_area_nodes
3671                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3672
3673         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3674         if(size_MB >= 1)
3675         {
3676                 infostream<<"initialEmerge: area: ";
3677                 block_area_nodes.print(infostream);
3678                 infostream<<" ("<<size_MB<<"MB)";
3679                 infostream<<std::endl;
3680         }
3681
3682         addArea(block_area_nodes);
3683
3684         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3685         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3686         for(s32 x=p_min.X; x<=p_max.X; x++)
3687         {
3688                 u8 flags = 0;
3689                 MapBlock *block;
3690                 v3s16 p(x,y,z);
3691                 std::map<v3s16, u8>::iterator n;
3692                 n = m_loaded_blocks.find(p);
3693                 if(n != m_loaded_blocks.end())
3694                         continue;
3695
3696                 bool block_data_inexistent = false;
3697                 try
3698                 {
3699                         TimeTaker timer1("emerge load", &emerge_load_time);
3700
3701                         block = m_map->getBlockNoCreate(p);
3702                         if(block->isDummy())
3703                                 block_data_inexistent = true;
3704                         else
3705                                 block->copyTo(*this);
3706                 }
3707                 catch(InvalidPositionException &e)
3708                 {
3709                         block_data_inexistent = true;
3710                 }
3711
3712                 if(block_data_inexistent)
3713                 {
3714
3715                         if (load_if_inexistent) {
3716                                 ServerMap *svrmap = (ServerMap *)m_map;
3717                                 block = svrmap->emergeBlock(p, false);
3718                                 if (block == NULL)
3719                                         block = svrmap->createBlock(p);
3720                                 else
3721                                         block->copyTo(*this);
3722                         } else {
3723                                 flags |= VMANIP_BLOCK_DATA_INEXIST;
3724
3725                                 /*
3726                                         Mark area inexistent
3727                                 */
3728                                 VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3729                                 // Fill with VOXELFLAG_NO_DATA
3730                                 for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3731                                 for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3732                                 {
3733                                         s32 i = m_area.index(a.MinEdge.X,y,z);
3734                                         memset(&m_flags[i], VOXELFLAG_NO_DATA, MAP_BLOCKSIZE);
3735                                 }
3736                         }
3737                 }
3738                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
3739                 {
3740                         // Mark that block was loaded as blank
3741                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
3742                 }*/
3743
3744                 m_loaded_blocks[p] = flags;
3745         }
3746 }
3747
3748 void ManualMapVoxelManipulator::blitBackAll(
3749                 std::map<v3s16, MapBlock*> * modified_blocks)
3750 {
3751         if(m_area.getExtent() == v3s16(0,0,0))
3752                 return;
3753
3754         /*
3755                 Copy data of all blocks
3756         */
3757         for(std::map<v3s16, u8>::iterator
3758                         i = m_loaded_blocks.begin();
3759                         i != m_loaded_blocks.end(); ++i)
3760         {
3761                 v3s16 p = i->first;
3762                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3763                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
3764                 if((existed == false) || (block == NULL))
3765                 {
3766                         continue;
3767                 }
3768
3769                 block->copyFrom(*this);
3770
3771                 if(modified_blocks)
3772                         (*modified_blocks)[p] = block;
3773         }
3774 }
3775
3776 //END