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