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