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