]> git.lizzy.rs Git - minetest.git/blob - src/map.cpp
Don't erase modified_blocks
[minetest.git] / src / map.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "map.h"
21 #include "mapsector.h"
22 #include "mapblock.h"
23 #include "main.h"
24 #include "filesys.h"
25 #include "voxel.h"
26 #include "porting.h"
27 #include "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 = 3;
2501         //v3s16 chunk_offset(-1,-1,-1);
2502         //s16 chunksize = 4;
2503         //v3s16 chunk_offset(-1,-1,-1);
2504         s16 chunksize = 5;
2505         v3s16 chunk_offset(-2,-2,-2);
2506         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2507         v3s16 blockpos_min = blockpos_div * chunksize;
2508         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2509         blockpos_min += chunk_offset;
2510         blockpos_max += chunk_offset;
2511
2512         //v3s16 extra_borders(1,1,1);
2513         v3s16 extra_borders(1,1,1);
2514
2515         // Do nothing if not inside limits (+-1 because of neighbors)
2516         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2517                 blockpos_over_limit(blockpos_max + extra_borders))
2518                 return false;
2519
2520         data->seed = m_seed;
2521         data->blockpos_min = blockpos_min;
2522         data->blockpos_max = blockpos_max;
2523         data->blockpos_requested = blockpos;
2524         data->nodedef = m_gamedef->ndef();
2525
2526         /*
2527                 Create the whole area of this and the neighboring blocks
2528         */
2529         {
2530                 //TimeTaker timer("initBlockMake() create area");
2531
2532                 for(s16 x=blockpos_min.X-extra_borders.X;
2533                                 x<=blockpos_max.X+extra_borders.X; x++)
2534                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2535                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2536                 {
2537                         v2s16 sectorpos(x, z);
2538                         // Sector metadata is loaded from disk if not already loaded.
2539                         ServerMapSector *sector = createSector(sectorpos);
2540                         assert(sector);
2541
2542                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2543                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2544                         {
2545                                 v3s16 p(x,y,z);
2546                                 //MapBlock *block = createBlock(p);
2547                                 // 1) get from memory, 2) load from disk
2548                                 MapBlock *block = emergeBlock(p, false);
2549                                 // 3) create a blank one
2550                                 if(block == NULL)
2551                                 {
2552                                         block = createBlock(p);
2553
2554                                         /*
2555                                                 Block gets sunlight if this is true.
2556
2557                                                 Refer to the map generator heuristics.
2558                                         */
2559                                         bool ug = m_emerge->isBlockUnderground(p);
2560                                         block->setIsUnderground(ug);
2561                                 }
2562
2563                                 // Lighting will not be valid after make_chunk is called
2564                                 block->setLightingExpired(true);
2565                                 // Lighting will be calculated
2566                                 //block->setLightingExpired(false);
2567                         }
2568                 }
2569         }
2570
2571         /*
2572                 Now we have a big empty area.
2573
2574                 Make a ManualMapVoxelManipulator that contains this and the
2575                 neighboring blocks
2576         */
2577
2578         // The area that contains this block and it's neighbors
2579         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2580         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2581
2582         data->vmanip = new ManualMapVoxelManipulator(this);
2583         //data->vmanip->setMap(this);
2584
2585         // Add the area
2586         {
2587                 //TimeTaker timer("initBlockMake() initialEmerge");
2588                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2589         }
2590         
2591         // Ensure none of the blocks to be generated were marked as containing CONTENT_IGNORE
2592 /*      for (s16 z = blockpos_min.Z; z <= blockpos_max.Z; z++) {
2593                 for (s16 y = blockpos_min.Y; y <= blockpos_max.Y; y++) {
2594                         for (s16 x = blockpos_min.X; x <= blockpos_max.X; x++) {
2595                                 core::map<v3s16, u8>::Node *n;
2596                                 n = data->vmanip->m_loaded_blocks.find(v3s16(x, y, z));
2597                                 if (n == NULL)
2598                                         continue;
2599                                 u8 flags = n->getValue();
2600                                 flags &= ~VMANIP_BLOCK_CONTAINS_CIGNORE;
2601                                 n->setValue(flags);
2602                         }
2603                 }
2604         }*/
2605
2606         // Data is ready now.
2607         return true;
2608 }
2609
2610 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
2611                 std::map<v3s16, MapBlock*> &changed_blocks)
2612 {
2613         v3s16 blockpos_min = data->blockpos_min;
2614         v3s16 blockpos_max = data->blockpos_max;
2615         v3s16 blockpos_requested = data->blockpos_requested;
2616         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2617                         <<blockpos_requested.Y<<","
2618                         <<blockpos_requested.Z<<")"<<std::endl;*/
2619
2620         v3s16 extra_borders(1,1,1);
2621
2622         bool enable_mapgen_debug_info = m_emerge->mapgen_debug_info;
2623
2624         /*infostream<<"Resulting vmanip:"<<std::endl;
2625         data->vmanip.print(infostream);*/
2626
2627         // Make sure affected blocks are loaded
2628         for(s16 x=blockpos_min.X-extra_borders.X;
2629                         x<=blockpos_max.X+extra_borders.X; x++)
2630         for(s16 z=blockpos_min.Z-extra_borders.Z;
2631                         z<=blockpos_max.Z+extra_borders.Z; z++)
2632         for(s16 y=blockpos_min.Y-extra_borders.Y;
2633                         y<=blockpos_max.Y+extra_borders.Y; y++)
2634         {
2635                 v3s16 p(x, y, z);
2636                 // Load from disk if not already in memory
2637                 emergeBlock(p, false);
2638         }
2639
2640         /*
2641                 Blit generated stuff to map
2642                 NOTE: blitBackAll adds nearly everything to changed_blocks
2643         */
2644         {
2645                 // 70ms @cs=8
2646                 //TimeTaker timer("finishBlockMake() blitBackAll");
2647                 data->vmanip->blitBackAll(&changed_blocks);
2648         }
2649
2650         EMERGE_DBG_OUT("finishBlockMake: changed_blocks.size()=" << changed_blocks.size());
2651
2652         /*
2653                 Copy transforming liquid information
2654         */
2655         while(data->transforming_liquid.size() > 0)
2656         {
2657                 v3s16 p = data->transforming_liquid.pop_front();
2658                 m_transforming_liquid.push_back(p);
2659         }
2660
2661         /*
2662                 Do stuff in central blocks
2663         */
2664
2665         /*
2666                 Update lighting
2667         */
2668         {
2669 #if 0
2670                 TimeTaker t("finishBlockMake lighting update");
2671
2672                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2673
2674                 // Center blocks
2675                 for(s16 x=blockpos_min.X-extra_borders.X;
2676                                 x<=blockpos_max.X+extra_borders.X; x++)
2677                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2678                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2679                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2680                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2681                 {
2682                         v3s16 p(x, y, z);
2683                         MapBlock *block = getBlockNoCreateNoEx(p);
2684                         assert(block);
2685                         lighting_update_blocks.insert(block->getPos(), block);
2686                 }
2687
2688                 updateLighting(lighting_update_blocks, changed_blocks);
2689 #endif
2690
2691                 /*
2692                         Set lighting to non-expired state in all of them.
2693                         This is cheating, but it is not fast enough if all of them
2694                         would actually be updated.
2695                 */
2696                 for(s16 x=blockpos_min.X-extra_borders.X;
2697                                 x<=blockpos_max.X+extra_borders.X; x++)
2698                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2699                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2700                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2701                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2702                 {
2703                         v3s16 p(x, y, z);
2704                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2705                 }
2706
2707 #if 0
2708                 if(enable_mapgen_debug_info == false)
2709                         t.stop(true); // Hide output
2710 #endif
2711         }
2712
2713         /*
2714                 Go through changed blocks
2715         */
2716         for(std::map<v3s16, MapBlock*>::iterator i = changed_blocks.begin();
2717                         i != changed_blocks.end(); ++i)
2718         {
2719                 MapBlock *block = i->second;
2720                 assert(block);
2721                 /*
2722                         Update day/night difference cache of the MapBlocks
2723                 */
2724                 block->expireDayNightDiff();
2725                 /*
2726                         Set block as modified
2727                 */
2728                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2729                                 "finishBlockMake expireDayNightDiff");
2730         }
2731
2732         /*
2733                 Set central blocks as generated
2734         */
2735         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2736         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2737         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2738         {
2739                 v3s16 p(x, y, z);
2740                 MapBlock *block = getBlockNoCreateNoEx(p);
2741                 assert(block);
2742                 block->setGenerated(true);
2743         }
2744
2745         /*
2746                 Save changed parts of map
2747                 NOTE: Will be saved later.
2748         */
2749         //save(MOD_STATE_WRITE_AT_UNLOAD);
2750
2751         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2752                         <<","<<blockpos_requested.Y<<","
2753                         <<blockpos_requested.Z<<")"<<std::endl;*/
2754 #if 0
2755         if(enable_mapgen_debug_info)
2756         {
2757                 /*
2758                         Analyze resulting blocks
2759                 */
2760                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2761                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2762                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2763                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2764                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2765                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2766                 {
2767                         v3s16 p = v3s16(x,y,z);
2768                         MapBlock *block = getBlockNoCreateNoEx(p);
2769                         char spos[20];
2770                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2771                         infostream<<"Generated "<<spos<<": "
2772                                         <<analyze_block(block)<<std::endl;
2773                 }
2774         }
2775 #endif
2776
2777         MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
2778         assert(block);
2779
2780         return block;
2781 }
2782
2783 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2784 {
2785         DSTACKF("%s: p2d=(%d,%d)",
2786                         __FUNCTION_NAME,
2787                         p2d.X, p2d.Y);
2788
2789         /*
2790                 Check if it exists already in memory
2791         */
2792         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2793         if(sector != NULL)
2794                 return sector;
2795
2796         /*
2797                 Try to load it from disk (with blocks)
2798         */
2799         //if(loadSectorFull(p2d) == true)
2800
2801         /*
2802                 Try to load metadata from disk
2803         */
2804 #if 0
2805         if(loadSectorMeta(p2d) == true)
2806         {
2807                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2808                 if(sector == NULL)
2809                 {
2810                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2811                         throw InvalidPositionException("");
2812                 }
2813                 return sector;
2814         }
2815 #endif
2816         /*
2817                 Do not create over-limit
2818         */
2819         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2820         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2821         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2822         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2823                 throw InvalidPositionException("createSector(): pos. over limit");
2824
2825         /*
2826                 Generate blank sector
2827         */
2828
2829         sector = new ServerMapSector(this, p2d, m_gamedef);
2830
2831         // Sector position on map in nodes
2832         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2833
2834         /*
2835                 Insert to container
2836         */
2837         m_sectors[p2d] = sector;
2838
2839         return sector;
2840 }
2841
2842 #if 0
2843 /*
2844         This is a quick-hand function for calling makeBlock().
2845 */
2846 MapBlock * ServerMap::generateBlock(
2847                 v3s16 p,
2848                 std::map<v3s16, MapBlock*> &modified_blocks
2849 )
2850 {
2851         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2852
2853         /*infostream<<"generateBlock(): "
2854                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2855                         <<std::endl;*/
2856
2857         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2858
2859         TimeTaker timer("generateBlock");
2860
2861         //MapBlock *block = original_dummy;
2862
2863         v2s16 p2d(p.X, p.Z);
2864         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2865
2866         /*
2867                 Do not generate over-limit
2868         */
2869         if(blockpos_over_limit(p))
2870         {
2871                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2872                 throw InvalidPositionException("generateBlock(): pos. over limit");
2873         }
2874
2875         /*
2876                 Create block make data
2877         */
2878         BlockMakeData data;
2879         initBlockMake(&data, p);
2880
2881         /*
2882                 Generate block
2883         */
2884         {
2885                 TimeTaker t("mapgen::make_block()");
2886                 mapgen->makeChunk(&data);
2887                 //mapgen::make_block(&data);
2888
2889                 if(enable_mapgen_debug_info == false)
2890                         t.stop(true); // Hide output
2891         }
2892
2893         /*
2894                 Blit data back on map, update lighting, add mobs and whatever this does
2895         */
2896         finishBlockMake(&data, modified_blocks);
2897
2898         /*
2899                 Get central block
2900         */
2901         MapBlock *block = getBlockNoCreateNoEx(p);
2902
2903 #if 0
2904         /*
2905                 Check result
2906         */
2907         if(block)
2908         {
2909                 bool erroneus_content = false;
2910                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2911                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2912                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2913                 {
2914                         v3s16 p(x0,y0,z0);
2915                         MapNode n = block->getNode(p);
2916                         if(n.getContent() == CONTENT_IGNORE)
2917                         {
2918                                 infostream<<"CONTENT_IGNORE at "
2919                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2920                                                 <<std::endl;
2921                                 erroneus_content = true;
2922                                 assert(0);
2923                         }
2924                 }
2925                 if(erroneus_content)
2926                 {
2927                         assert(0);
2928                 }
2929         }
2930 #endif
2931
2932 #if 0
2933         /*
2934                 Generate a completely empty block
2935         */
2936         if(block)
2937         {
2938                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2939                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2940                 {
2941                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2942                         {
2943                                 MapNode n;
2944                                 n.setContent(CONTENT_AIR);
2945                                 block->setNode(v3s16(x0,y0,z0), n);
2946                         }
2947                 }
2948         }
2949 #endif
2950
2951         if(enable_mapgen_debug_info == false)
2952                 timer.stop(true); // Hide output
2953
2954         return block;
2955 }
2956 #endif
2957
2958 MapBlock * ServerMap::createBlock(v3s16 p)
2959 {
2960         DSTACKF("%s: p=(%d,%d,%d)",
2961                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2962
2963         /*
2964                 Do not create over-limit
2965         */
2966         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2967         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2968         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2969         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2970         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2971         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2972                 throw InvalidPositionException("createBlock(): pos. over limit");
2973
2974         v2s16 p2d(p.X, p.Z);
2975         s16 block_y = p.Y;
2976         /*
2977                 This will create or load a sector if not found in memory.
2978                 If block exists on disk, it will be loaded.
2979
2980                 NOTE: On old save formats, this will be slow, as it generates
2981                       lighting on blocks for them.
2982         */
2983         ServerMapSector *sector;
2984         try{
2985                 sector = (ServerMapSector*)createSector(p2d);
2986                 assert(sector->getId() == MAPSECTOR_SERVER);
2987         }
2988         catch(InvalidPositionException &e)
2989         {
2990                 infostream<<"createBlock: createSector() failed"<<std::endl;
2991                 throw e;
2992         }
2993         /*
2994                 NOTE: This should not be done, or at least the exception
2995                 should not be passed on as std::exception, because it
2996                 won't be catched at all.
2997         */
2998         /*catch(std::exception &e)
2999         {
3000                 infostream<<"createBlock: createSector() failed: "
3001                                 <<e.what()<<std::endl;
3002                 throw e;
3003         }*/
3004
3005         /*
3006                 Try to get a block from the sector
3007         */
3008
3009         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
3010         if(block)
3011         {
3012                 if(block->isDummy())
3013                         block->unDummify();
3014                 return block;
3015         }
3016         // Create blank
3017         block = sector->createBlankBlock(block_y);
3018
3019         return block;
3020 }
3021
3022 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
3023 {
3024         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
3025                         __FUNCTION_NAME,
3026                         p.X, p.Y, p.Z, create_blank);
3027
3028         {
3029                 MapBlock *block = getBlockNoCreateNoEx(p);
3030                 if(block && block->isDummy() == false)
3031                         return block;
3032         }
3033
3034         {
3035                 MapBlock *block = loadBlock(p);
3036                 if(block)
3037                         return block;
3038         }
3039
3040         if (create_blank) {
3041                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
3042                 MapBlock *block = sector->createBlankBlock(p.Y);
3043
3044                 return block;
3045         }
3046         /*if(allow_generate)
3047         {
3048                 std::map<v3s16, MapBlock*> modified_blocks;
3049                 MapBlock *block = generateBlock(p, modified_blocks);
3050                 if(block)
3051                 {
3052                         MapEditEvent event;
3053                         event.type = MEET_OTHER;
3054                         event.p = p;
3055
3056                         // Copy modified_blocks to event
3057                         for(std::map<v3s16, MapBlock*>::iterator
3058                                         i = modified_blocks.begin();
3059                                         i != modified_blocks.end(); ++i)
3060                         {
3061                                 event.modified_blocks.insert(i->first);
3062                         }
3063
3064                         // Queue event
3065                         dispatchEvent(&event);
3066
3067                         return block;
3068                 }
3069         }*/
3070
3071         return NULL;
3072 }
3073
3074 s16 ServerMap::findGroundLevel(v2s16 p2d)
3075 {
3076 #if 0
3077         /*
3078                 Uh, just do something random...
3079         */
3080         // Find existing map from top to down
3081         s16 max=63;
3082         s16 min=-64;
3083         v3s16 p(p2d.X, max, p2d.Y);
3084         for(; p.Y>min; p.Y--)
3085         {
3086                 MapNode n = getNodeNoEx(p);
3087                 if(n.getContent() != CONTENT_IGNORE)
3088                         break;
3089         }
3090         if(p.Y == min)
3091                 goto plan_b;
3092         // If this node is not air, go to plan b
3093         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
3094                 goto plan_b;
3095         // Search existing walkable and return it
3096         for(; p.Y>min; p.Y--)
3097         {
3098                 MapNode n = getNodeNoEx(p);
3099                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
3100                         return p.Y;
3101         }
3102
3103         // Move to plan b
3104 plan_b:
3105 #endif
3106
3107         /*
3108                 Determine from map generator noise functions
3109         */
3110
3111         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
3112         return level;
3113
3114         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
3115         //return (s16)level;
3116 }
3117
3118 void ServerMap::createDatabase() {
3119         int e;
3120         assert(m_database);
3121         e = sqlite3_exec(m_database,
3122                 "CREATE TABLE IF NOT EXISTS `blocks` ("
3123                         "`pos` INT NOT NULL PRIMARY KEY,"
3124                         "`data` BLOB"
3125                 ");"
3126         , NULL, NULL, NULL);
3127         if(e == SQLITE_ABORT)
3128                 throw FileNotGoodException("Could not create database structure");
3129         else
3130                 infostream<<"ServerMap: Database structure was created";
3131 }
3132
3133 void ServerMap::verifyDatabase() {
3134         if(m_database)
3135                 return;
3136
3137         {
3138                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
3139                 bool needs_create = false;
3140                 int d;
3141
3142                 /*
3143                         Open the database connection
3144                 */
3145
3146                 createDirs(m_savedir);
3147
3148                 if(!fs::PathExists(dbp))
3149                         needs_create = true;
3150
3151                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
3152                 if(d != SQLITE_OK) {
3153                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
3154                         throw FileNotGoodException("Cannot open database file");
3155                 }
3156
3157                 if(needs_create)
3158                         createDatabase();
3159
3160                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
3161                 if(d != SQLITE_OK) {
3162                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3163                         throw FileNotGoodException("Cannot prepare read statement");
3164                 }
3165
3166                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
3167                 if(d != SQLITE_OK) {
3168                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3169                         throw FileNotGoodException("Cannot prepare write statement");
3170                 }
3171
3172                 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
3173                 if(d != SQLITE_OK) {
3174                         infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
3175                         throw FileNotGoodException("Cannot prepare read statement");
3176                 }
3177
3178                 infostream<<"ServerMap: Database opened"<<std::endl;
3179         }
3180 }
3181
3182 bool ServerMap::loadFromFolders() {
3183         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
3184                 return true;
3185         return false;
3186 }
3187
3188 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
3189         return (sqlite3_int64)pos.Z*16777216 +
3190                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
3191 }
3192
3193 void ServerMap::createDirs(std::string path)
3194 {
3195         if(fs::CreateAllDirs(path) == false)
3196         {
3197                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
3198                                 <<"\""<<path<<"\""<<std::endl;
3199                 throw BaseException("ServerMap failed to create directory");
3200         }
3201 }
3202
3203 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
3204 {
3205         char cc[9];
3206         switch(layout)
3207         {
3208                 case 1:
3209                         snprintf(cc, 9, "%.4x%.4x",
3210                                 (unsigned int)pos.X&0xffff,
3211                                 (unsigned int)pos.Y&0xffff);
3212
3213                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
3214                 case 2:
3215                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
3216                                 (unsigned int)pos.X&0xfff,
3217                                 (unsigned int)pos.Y&0xfff);
3218
3219                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
3220                 default:
3221                         assert(false);
3222         }
3223 }
3224
3225 v2s16 ServerMap::getSectorPos(std::string dirname)
3226 {
3227         unsigned int x, y;
3228         int r;
3229         size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
3230         assert(spos != std::string::npos);
3231         if(dirname.size() - spos == 8)
3232         {
3233                 // Old layout
3234                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
3235         }
3236         else if(dirname.size() - spos == 3)
3237         {
3238                 // New layout
3239                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
3240                 // Sign-extend the 12 bit values up to 16 bits...
3241                 if(x&0x800) x|=0xF000;
3242                 if(y&0x800) y|=0xF000;
3243         }
3244         else
3245         {
3246                 assert(false);
3247         }
3248         assert(r == 2);
3249         v2s16 pos((s16)x, (s16)y);
3250         return pos;
3251 }
3252
3253 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
3254 {
3255         v2s16 p2d = getSectorPos(sectordir);
3256
3257         if(blockfile.size() != 4){
3258                 throw InvalidFilenameException("Invalid block filename");
3259         }
3260         unsigned int y;
3261         int r = sscanf(blockfile.c_str(), "%4x", &y);
3262         if(r != 1)
3263                 throw InvalidFilenameException("Invalid block filename");
3264         return v3s16(p2d.X, y, p2d.Y);
3265 }
3266
3267 std::string ServerMap::getBlockFilename(v3s16 p)
3268 {
3269         char cc[5];
3270         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
3271         return cc;
3272 }
3273
3274 void ServerMap::save(ModifiedState save_level)
3275 {
3276         DSTACK(__FUNCTION_NAME);
3277         if(m_map_saving_enabled == false)
3278         {
3279                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
3280                 return;
3281         }
3282
3283         if(save_level == MOD_STATE_CLEAN)
3284                 infostream<<"ServerMap: Saving whole map, this can take time."
3285                                 <<std::endl;
3286
3287         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
3288         {
3289                 saveMapMeta();
3290         }
3291
3292         // Profile modified reasons
3293         Profiler modprofiler;
3294
3295         u32 sector_meta_count = 0;
3296         u32 block_count = 0;
3297         u32 block_count_all = 0; // Number of blocks in memory
3298
3299         // Don't do anything with sqlite unless something is really saved
3300         bool save_started = false;
3301
3302         for(std::map<v2s16, MapSector*>::iterator i = m_sectors.begin();
3303                 i != m_sectors.end(); ++i)
3304         {
3305                 ServerMapSector *sector = (ServerMapSector*)i->second;
3306                 assert(sector->getId() == MAPSECTOR_SERVER);
3307
3308                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
3309                 {
3310                         saveSectorMeta(sector);
3311                         sector_meta_count++;
3312                 }
3313                 std::list<MapBlock*> blocks;
3314                 sector->getBlocks(blocks);
3315
3316                 for(std::list<MapBlock*>::iterator j = blocks.begin();
3317                         j != blocks.end(); ++j)
3318                 {
3319                         MapBlock *block = *j;
3320
3321                         block_count_all++;
3322
3323                         if(block->getModified() >= (u32)save_level)
3324                         {
3325                                 // Lazy beginSave()
3326                                 if(!save_started){
3327                                         beginSave();
3328                                         save_started = true;
3329                                 }
3330
3331                                 modprofiler.add(block->getModifiedReason(), 1);
3332
3333                                 saveBlock(block);
3334                                 block_count++;
3335
3336                                 /*infostream<<"ServerMap: Written block ("
3337                                                 <<block->getPos().X<<","
3338                                                 <<block->getPos().Y<<","
3339                                                 <<block->getPos().Z<<")"
3340                                                 <<std::endl;*/
3341                         }
3342                 }
3343         }
3344         if(save_started)
3345                 endSave();
3346
3347         /*
3348                 Only print if something happened or saved whole map
3349         */
3350         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
3351                         || block_count != 0)
3352         {
3353                 infostream<<"ServerMap: Written: "
3354                                 <<sector_meta_count<<" sector metadata files, "
3355                                 <<block_count<<" block files"
3356                                 <<", "<<block_count_all<<" blocks in memory."
3357                                 <<std::endl;
3358                 PrintInfo(infostream); // ServerMap/ClientMap:
3359                 infostream<<"Blocks modified by: "<<std::endl;
3360                 modprofiler.print(infostream);
3361         }
3362 }
3363
3364 static s32 unsignedToSigned(s32 i, s32 max_positive)
3365 {
3366         if(i < max_positive)
3367                 return i;
3368         else
3369                 return i - 2*max_positive;
3370 }
3371
3372 // modulo of a negative number does not work consistently in C
3373 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
3374 {
3375         if(i >= 0)
3376                 return i % mod;
3377         return mod - ((-i) % mod);
3378 }
3379
3380 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
3381 {
3382         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3383         i = (i - x) / 4096;
3384         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3385         i = (i - y) / 4096;
3386         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3387         return v3s16(x,y,z);
3388 }
3389
3390 void ServerMap::listAllLoadableBlocks(std::list<v3s16> &dst)
3391 {
3392         if(loadFromFolders()){
3393                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
3394                                 <<"all blocks that are stored in flat files"<<std::endl;
3395         }
3396
3397         {
3398                 verifyDatabase();
3399
3400                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
3401                 {
3402                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
3403                         v3s16 p = getIntegerAsBlock(block_i);
3404                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
3405                         dst.push_back(p);
3406                 }
3407         }
3408 }
3409
3410 void ServerMap::saveMapMeta()
3411 {
3412         DSTACK(__FUNCTION_NAME);
3413
3414         /*infostream<<"ServerMap::saveMapMeta(): "
3415                         <<"seed="<<m_seed
3416                         <<std::endl;*/
3417
3418         createDirs(m_savedir);
3419
3420         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3421         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
3422         if(os.good() == false)
3423         {
3424                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3425                                 <<"could not open"<<fullpath<<std::endl;
3426                 throw FileNotGoodException("Cannot open chunk metadata");
3427         }
3428
3429         Settings params;
3430
3431         m_emerge->setParamsToSettings(&params);
3432         params.writeLines(os);
3433
3434         os<<"[end_of_params]\n";
3435
3436         m_map_metadata_changed = false;
3437 }
3438
3439 void ServerMap::loadMapMeta()
3440 {
3441         DSTACK(__FUNCTION_NAME);
3442
3443         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3444                         <<std::endl;*/
3445
3446         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3447         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3448         if(is.good() == false)
3449         {
3450                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3451                                 <<"could not open"<<fullpath<<std::endl;
3452                 throw FileNotGoodException("Cannot open map metadata");
3453         }
3454
3455         Settings params;
3456
3457         for(;;)
3458         {
3459                 if(is.eof())
3460                         throw SerializationError
3461                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3462                 std::string line;
3463                 std::getline(is, line);
3464                 std::string trimmedline = trim(line);
3465                 if(trimmedline == "[end_of_params]")
3466                         break;
3467                 params.parseConfigLine(line);
3468         }
3469
3470         MapgenParams *mgparams = m_emerge->getParamsFromSettings(&params);
3471         if (mgparams) {
3472                 if (m_mgparams)
3473                         delete m_mgparams;
3474                 m_mgparams = mgparams;
3475                 m_seed = mgparams->seed;
3476         } else {
3477                 if (params.exists("seed")) {
3478                         m_seed = params.getU64("seed");
3479                         m_mgparams->seed = m_seed;
3480                 }
3481         }
3482
3483         verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3484 }
3485
3486 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3487 {
3488         DSTACK(__FUNCTION_NAME);
3489         // Format used for writing
3490         u8 version = SER_FMT_VER_HIGHEST;
3491         // Get destination
3492         v2s16 pos = sector->getPos();
3493         std::string dir = getSectorDir(pos);
3494         createDirs(dir);
3495
3496         std::string fullpath = dir + DIR_DELIM + "meta";
3497         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3498         if(o.good() == false)
3499                 throw FileNotGoodException("Cannot open sector metafile");
3500
3501         sector->serialize(o, version);
3502
3503         sector->differs_from_disk = false;
3504 }
3505
3506 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3507 {
3508         DSTACK(__FUNCTION_NAME);
3509         // Get destination
3510         v2s16 p2d = getSectorPos(sectordir);
3511
3512         ServerMapSector *sector = NULL;
3513
3514         std::string fullpath = sectordir + DIR_DELIM + "meta";
3515         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3516         if(is.good() == false)
3517         {
3518                 // If the directory exists anyway, it probably is in some old
3519                 // format. Just go ahead and create the sector.
3520                 if(fs::PathExists(sectordir))
3521                 {
3522                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3523                                         <<fullpath<<" doesn't exist but directory does."
3524                                         <<" Continuing with a sector with no metadata."
3525                                         <<std::endl;*/
3526                         sector = new ServerMapSector(this, p2d, m_gamedef);
3527                         m_sectors[p2d] = sector;
3528                 }
3529                 else
3530                 {
3531                         throw FileNotGoodException("Cannot open sector metafile");
3532                 }
3533         }
3534         else
3535         {
3536                 sector = ServerMapSector::deSerialize
3537                                 (is, this, p2d, m_sectors, m_gamedef);
3538                 if(save_after_load)
3539                         saveSectorMeta(sector);
3540         }
3541
3542         sector->differs_from_disk = false;
3543
3544         return sector;
3545 }
3546
3547 bool ServerMap::loadSectorMeta(v2s16 p2d)
3548 {
3549         DSTACK(__FUNCTION_NAME);
3550
3551         MapSector *sector = NULL;
3552
3553         // The directory layout we're going to load from.
3554         //  1 - original sectors/xxxxzzzz/
3555         //  2 - new sectors2/xxx/zzz/
3556         //  If we load from anything but the latest structure, we will
3557         //  immediately save to the new one, and remove the old.
3558         int loadlayout = 1;
3559         std::string sectordir1 = getSectorDir(p2d, 1);
3560         std::string sectordir;
3561         if(fs::PathExists(sectordir1))
3562         {
3563                 sectordir = sectordir1;
3564         }
3565         else
3566         {
3567                 loadlayout = 2;
3568                 sectordir = getSectorDir(p2d, 2);
3569         }
3570
3571         try{
3572                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3573         }
3574         catch(InvalidFilenameException &e)
3575         {
3576                 return false;
3577         }
3578         catch(FileNotGoodException &e)
3579         {
3580                 return false;
3581         }
3582         catch(std::exception &e)
3583         {
3584                 return false;
3585         }
3586
3587         return true;
3588 }
3589
3590 #if 0
3591 bool ServerMap::loadSectorFull(v2s16 p2d)
3592 {
3593         DSTACK(__FUNCTION_NAME);
3594
3595         MapSector *sector = NULL;
3596
3597         // The directory layout we're going to load from.
3598         //  1 - original sectors/xxxxzzzz/
3599         //  2 - new sectors2/xxx/zzz/
3600         //  If we load from anything but the latest structure, we will
3601         //  immediately save to the new one, and remove the old.
3602         int loadlayout = 1;
3603         std::string sectordir1 = getSectorDir(p2d, 1);
3604         std::string sectordir;
3605         if(fs::PathExists(sectordir1))
3606         {
3607                 sectordir = sectordir1;
3608         }
3609         else
3610         {
3611                 loadlayout = 2;
3612                 sectordir = getSectorDir(p2d, 2);
3613         }
3614
3615         try{
3616                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3617         }
3618         catch(InvalidFilenameException &e)
3619         {
3620                 return false;
3621         }
3622         catch(FileNotGoodException &e)
3623         {
3624                 return false;
3625         }
3626         catch(std::exception &e)
3627         {
3628                 return false;
3629         }
3630
3631         /*
3632                 Load blocks
3633         */
3634         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3635                         (sectordir);
3636         std::vector<fs::DirListNode>::iterator i2;
3637         for(i2=list2.begin(); i2!=list2.end(); i2++)
3638         {
3639                 // We want files
3640                 if(i2->dir)
3641                         continue;
3642                 try{
3643                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3644                 }
3645                 catch(InvalidFilenameException &e)
3646                 {
3647                         // This catches unknown crap in directory
3648                 }
3649         }
3650
3651         if(loadlayout != 2)
3652         {
3653                 infostream<<"Sector converted to new layout - deleting "<<
3654                         sectordir1<<std::endl;
3655                 fs::RecursiveDelete(sectordir1);
3656         }
3657
3658         return true;
3659 }
3660 #endif
3661
3662 void ServerMap::beginSave() {
3663         verifyDatabase();
3664         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3665                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3666 }
3667
3668 void ServerMap::endSave() {
3669         verifyDatabase();
3670         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3671                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3672 }
3673
3674 void ServerMap::saveBlock(MapBlock *block)
3675 {
3676         DSTACK(__FUNCTION_NAME);
3677         /*
3678                 Dummy blocks are not written
3679         */
3680         if(block->isDummy())
3681         {
3682                 /*v3s16 p = block->getPos();
3683                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3684                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3685                 return;
3686         }
3687
3688         // Format used for writing
3689         u8 version = SER_FMT_VER_HIGHEST;
3690         // Get destination
3691         v3s16 p3d = block->getPos();
3692
3693
3694 #if 0
3695         v2s16 p2d(p3d.X, p3d.Z);
3696         std::string sectordir = getSectorDir(p2d);
3697
3698         createDirs(sectordir);
3699
3700         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3701         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3702         if(o.good() == false)
3703                 throw FileNotGoodException("Cannot open block data");
3704 #endif
3705         /*
3706                 [0] u8 serialization version
3707                 [1] data
3708         */
3709
3710         verifyDatabase();
3711
3712         std::ostringstream o(std::ios_base::binary);
3713
3714         o.write((char*)&version, 1);
3715
3716         // Write basic data
3717         block->serialize(o, version, true);
3718
3719         // Write block to database
3720
3721         std::string tmp = o.str();
3722         const char *bytes = tmp.c_str();
3723
3724         bool success = true;
3725         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
3726                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3727                 success = false;
3728         }
3729         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) { // TODO this mught not be the right length
3730                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3731                 success = false;
3732         }
3733         int written = sqlite3_step(m_database_write);
3734         if(written != SQLITE_DONE) {
3735                 errorstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3736                                 <<sqlite3_errmsg(m_database)<<std::endl;
3737                 success = false;
3738         }
3739         // Make ready for later reuse
3740         sqlite3_reset(m_database_write);
3741
3742         // We just wrote it to the disk so clear modified flag
3743         if (success)
3744                 block->resetModified();
3745 }
3746
3747 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3748 {
3749         DSTACK(__FUNCTION_NAME);
3750
3751         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3752         try{
3753
3754                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3755                 if(is.good() == false)
3756                         throw FileNotGoodException("Cannot open block file");
3757
3758                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3759                 v2s16 p2d(p3d.X, p3d.Z);
3760
3761                 assert(sector->getPos() == p2d);
3762
3763                 u8 version = SER_FMT_VER_INVALID;
3764                 is.read((char*)&version, 1);
3765
3766                 if(is.fail())
3767                         throw SerializationError("ServerMap::loadBlock(): Failed"
3768                                         " to read MapBlock version");
3769
3770                 /*u32 block_size = MapBlock::serializedLength(version);
3771                 SharedBuffer<u8> data(block_size);
3772                 is.read((char*)*data, block_size);*/
3773
3774                 // This will always return a sector because we're the server
3775                 //MapSector *sector = emergeSector(p2d);
3776
3777                 MapBlock *block = NULL;
3778                 bool created_new = false;
3779                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3780                 if(block == NULL)
3781                 {
3782                         block = sector->createBlankBlockNoInsert(p3d.Y);
3783                         created_new = true;
3784                 }
3785
3786                 // Read basic data
3787                 block->deSerialize(is, version, true);
3788
3789                 // If it's a new block, insert it to the map
3790                 if(created_new)
3791                         sector->insertBlock(block);
3792
3793                 /*
3794                         Save blocks loaded in old format in new format
3795                 */
3796
3797                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3798                 {
3799                         saveBlock(block);
3800
3801                         // Should be in database now, so delete the old file
3802                         fs::RecursiveDelete(fullpath);
3803                 }
3804
3805                 // We just loaded it from the disk, so it's up-to-date.
3806                 block->resetModified();
3807
3808         }
3809         catch(SerializationError &e)
3810         {
3811                 infostream<<"WARNING: Invalid block data on disk "
3812                                 <<"fullpath="<<fullpath
3813                                 <<" (SerializationError). "
3814                                 <<"what()="<<e.what()
3815                                 <<std::endl;
3816                                 //" Ignoring. A new one will be generated.
3817                 assert(0);
3818
3819                 // TODO: Backup file; name is in fullpath.
3820         }
3821 }
3822
3823 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3824 {
3825         DSTACK(__FUNCTION_NAME);
3826
3827         try {
3828                 std::istringstream is(*blob, std::ios_base::binary);
3829
3830                 u8 version = SER_FMT_VER_INVALID;
3831                 is.read((char*)&version, 1);
3832
3833                 if(is.fail())
3834                         throw SerializationError("ServerMap::loadBlock(): Failed"
3835                                         " to read MapBlock version");
3836
3837                 /*u32 block_size = MapBlock::serializedLength(version);
3838                 SharedBuffer<u8> data(block_size);
3839                 is.read((char*)*data, block_size);*/
3840
3841                 // This will always return a sector because we're the server
3842                 //MapSector *sector = emergeSector(p2d);
3843
3844                 MapBlock *block = NULL;
3845                 bool created_new = false;
3846                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3847                 if(block == NULL)
3848                 {
3849                         block = sector->createBlankBlockNoInsert(p3d.Y);
3850                         created_new = true;
3851                 }
3852
3853                 // Read basic data
3854                 block->deSerialize(is, version, true);
3855
3856                 // If it's a new block, insert it to the map
3857                 if(created_new)
3858                         sector->insertBlock(block);
3859
3860                 /*
3861                         Save blocks loaded in old format in new format
3862                 */
3863
3864                 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
3865                 // Only save if asked to; no need to update version
3866                 if(save_after_load)
3867                         saveBlock(block);
3868
3869                 // We just loaded it from, so it's up-to-date.
3870                 block->resetModified();
3871
3872         }
3873         catch(SerializationError &e)
3874         {
3875                 errorstream<<"Invalid block data in database"
3876                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3877                                 <<" (SerializationError): "<<e.what()<<std::endl;
3878
3879                 // TODO: Block should be marked as invalid in memory so that it is
3880                 // not touched but the game can run
3881
3882                 if(g_settings->getBool("ignore_world_load_errors")){
3883                         errorstream<<"Ignoring block load error. Duck and cover! "
3884                                         <<"(ignore_world_load_errors)"<<std::endl;
3885                 } else {
3886                         throw SerializationError("Invalid block data in database");
3887                         //assert(0);
3888                 }
3889         }
3890 }
3891
3892 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3893 {
3894         DSTACK(__FUNCTION_NAME);
3895
3896         v2s16 p2d(blockpos.X, blockpos.Z);
3897
3898         if(!loadFromFolders()) {
3899                 verifyDatabase();
3900
3901                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3902                         infostream<<"WARNING: Could not bind block position for load: "
3903                                 <<sqlite3_errmsg(m_database)<<std::endl;
3904                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3905                         /*
3906                                 Make sure sector is loaded
3907                         */
3908                         MapSector *sector = createSector(p2d);
3909
3910                         /*
3911                                 Load block
3912                         */
3913                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3914                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3915
3916                         std::string datastr(data, len);
3917
3918                         loadBlock(&datastr, blockpos, sector, false);
3919
3920                         sqlite3_step(m_database_read);
3921                         // We should never get more than 1 row, so ok to reset
3922                         sqlite3_reset(m_database_read);
3923
3924                         return getBlockNoCreateNoEx(blockpos);
3925                 }
3926                 sqlite3_reset(m_database_read);
3927
3928                 // Not found in database, try the files
3929         }
3930
3931         // The directory layout we're going to load from.
3932         //  1 - original sectors/xxxxzzzz/
3933         //  2 - new sectors2/xxx/zzz/
3934         //  If we load from anything but the latest structure, we will
3935         //  immediately save to the new one, and remove the old.
3936         int loadlayout = 1;
3937         std::string sectordir1 = getSectorDir(p2d, 1);
3938         std::string sectordir;
3939         if(fs::PathExists(sectordir1))
3940         {
3941                 sectordir = sectordir1;
3942         }
3943         else
3944         {
3945                 loadlayout = 2;
3946                 sectordir = getSectorDir(p2d, 2);
3947         }
3948
3949         /*
3950                 Make sure sector is loaded
3951         */
3952         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3953         if(sector == NULL)
3954         {
3955                 try{
3956                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3957                 }
3958                 catch(InvalidFilenameException &e)
3959                 {
3960                         return NULL;
3961                 }
3962                 catch(FileNotGoodException &e)
3963                 {
3964                         return NULL;
3965                 }
3966                 catch(std::exception &e)
3967                 {
3968                         return NULL;
3969                 }
3970         }
3971
3972         /*
3973                 Make sure file exists
3974         */
3975
3976         std::string blockfilename = getBlockFilename(blockpos);
3977         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3978                 return NULL;
3979
3980         /*
3981                 Load block and save it to the database
3982         */
3983         loadBlock(sectordir, blockfilename, sector, true);
3984         return getBlockNoCreateNoEx(blockpos);
3985 }
3986
3987 void ServerMap::PrintInfo(std::ostream &out)
3988 {
3989         out<<"ServerMap: ";
3990 }
3991
3992 /*
3993         MapVoxelManipulator
3994 */
3995
3996 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3997 {
3998         m_map = map;
3999 }
4000
4001 MapVoxelManipulator::~MapVoxelManipulator()
4002 {
4003         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
4004                         <<std::endl;*/
4005 }
4006
4007 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4008 {
4009         TimeTaker timer1("emerge", &emerge_time);
4010
4011         // Units of these are MapBlocks
4012         v3s16 p_min = getNodeBlockPos(a.MinEdge);
4013         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
4014
4015         VoxelArea block_area_nodes
4016                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4017
4018         addArea(block_area_nodes);
4019
4020         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4021         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4022         for(s32 x=p_min.X; x<=p_max.X; x++)
4023         {
4024                 u8 flags = 0;
4025                 MapBlock *block;
4026                 v3s16 p(x,y,z);
4027                 std::map<v3s16, u8>::iterator n;
4028                 n = m_loaded_blocks.find(p);
4029                 if(n != m_loaded_blocks.end())
4030                         continue;
4031
4032                 bool block_data_inexistent = false;
4033                 try
4034                 {
4035                         TimeTaker timer1("emerge load", &emerge_load_time);
4036
4037                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
4038                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
4039                                         <<" wanted area: ";
4040                         a.print(infostream);
4041                         infostream<<std::endl;*/
4042
4043                         block = m_map->getBlockNoCreate(p);
4044                         if(block->isDummy())
4045                                 block_data_inexistent = true;
4046                         else
4047                                 block->copyTo(*this);
4048                 }
4049                 catch(InvalidPositionException &e)
4050                 {
4051                         block_data_inexistent = true;
4052                 }
4053
4054                 if(block_data_inexistent)
4055                 {
4056                         flags |= VMANIP_BLOCK_DATA_INEXIST;
4057
4058                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4059                         // Fill with VOXELFLAG_INEXISTENT
4060                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4061                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4062                         {
4063                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4064                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4065                         }
4066                 }
4067                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4068                 {
4069                         // Mark that block was loaded as blank
4070                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4071                 }*/
4072
4073                 m_loaded_blocks[p] = flags;
4074         }
4075
4076         //infostream<<"emerge done"<<std::endl;
4077 }
4078
4079 /*
4080         SUGG: Add an option to only update eg. water and air nodes.
4081               This will make it interfere less with important stuff if
4082                   run on background.
4083 */
4084 void MapVoxelManipulator::blitBack
4085                 (std::map<v3s16, MapBlock*> & modified_blocks)
4086 {
4087         if(m_area.getExtent() == v3s16(0,0,0))
4088                 return;
4089
4090         //TimeTaker timer1("blitBack");
4091
4092         /*infostream<<"blitBack(): m_loaded_blocks.size()="
4093                         <<m_loaded_blocks.size()<<std::endl;*/
4094
4095         /*
4096                 Initialize block cache
4097         */
4098         v3s16 blockpos_last;
4099         MapBlock *block = NULL;
4100         bool block_checked_in_modified = false;
4101
4102         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
4103         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
4104         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
4105         {
4106                 v3s16 p(x,y,z);
4107
4108                 u8 f = m_flags[m_area.index(p)];
4109                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
4110                         continue;
4111
4112                 MapNode &n = m_data[m_area.index(p)];
4113
4114                 v3s16 blockpos = getNodeBlockPos(p);
4115
4116                 try
4117                 {
4118                         // Get block
4119                         if(block == NULL || blockpos != blockpos_last){
4120                                 block = m_map->getBlockNoCreate(blockpos);
4121                                 blockpos_last = blockpos;
4122                                 block_checked_in_modified = false;
4123                         }
4124
4125                         // Calculate relative position in block
4126                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
4127
4128                         // Don't continue if nothing has changed here
4129                         if(block->getNode(relpos) == n)
4130                                 continue;
4131
4132                         //m_map->setNode(m_area.MinEdge + p, n);
4133                         block->setNode(relpos, n);
4134
4135                         /*
4136                                 Make sure block is in modified_blocks
4137                         */
4138                         if(block_checked_in_modified == false)
4139                         {
4140                                 modified_blocks[blockpos] = block;
4141                                 block_checked_in_modified = true;
4142                         }
4143                 }
4144                 catch(InvalidPositionException &e)
4145                 {
4146                 }
4147         }
4148 }
4149
4150 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
4151                 MapVoxelManipulator(map),
4152                 m_create_area(false)
4153 {
4154 }
4155
4156 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
4157 {
4158 }
4159
4160 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
4161 {
4162         // Just create the area so that it can be pointed to
4163         VoxelManipulator::emerge(a, caller_id);
4164 }
4165
4166 void ManualMapVoxelManipulator::initialEmerge(
4167                 v3s16 blockpos_min, v3s16 blockpos_max)
4168 {
4169         TimeTaker timer1("initialEmerge", &emerge_time);
4170
4171         // Units of these are MapBlocks
4172         v3s16 p_min = blockpos_min;
4173         v3s16 p_max = blockpos_max;
4174
4175         VoxelArea block_area_nodes
4176                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4177
4178         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
4179         if(size_MB >= 1)
4180         {
4181                 infostream<<"initialEmerge: area: ";
4182                 block_area_nodes.print(infostream);
4183                 infostream<<" ("<<size_MB<<"MB)";
4184                 infostream<<std::endl;
4185         }
4186
4187         addArea(block_area_nodes);
4188
4189         for(s32 z=p_min.Z; z<=p_max.Z; z++)
4190         for(s32 y=p_min.Y; y<=p_max.Y; y++)
4191         for(s32 x=p_min.X; x<=p_max.X; x++)
4192         {
4193                 u8 flags = 0;
4194                 MapBlock *block;
4195                 v3s16 p(x,y,z);
4196                 std::map<v3s16, u8>::iterator n;
4197                 n = m_loaded_blocks.find(p);
4198                 if(n != m_loaded_blocks.end())
4199                         continue;
4200
4201                 bool block_data_inexistent = false;
4202                 try
4203                 {
4204                         TimeTaker timer1("emerge load", &emerge_load_time);
4205
4206                         block = m_map->getBlockNoCreate(p);
4207                         if(block->isDummy())
4208                                 block_data_inexistent = true;
4209                         else
4210                                 block->copyTo(*this);
4211                 }
4212                 catch(InvalidPositionException &e)
4213                 {
4214                         block_data_inexistent = true;
4215                 }
4216
4217                 if(block_data_inexistent)
4218                 {
4219                         flags |= VMANIP_BLOCK_DATA_INEXIST;
4220                         
4221                         /*
4222                                 Mark area inexistent
4223                         */
4224                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
4225                         // Fill with VOXELFLAG_INEXISTENT
4226                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
4227                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
4228                         {
4229                                 s32 i = m_area.index(a.MinEdge.X,y,z);
4230                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
4231                         }
4232                 }
4233                 /*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
4234                 {
4235                         // Mark that block was loaded as blank
4236                         flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
4237                 }*/
4238
4239                 m_loaded_blocks[p] = flags;
4240         }
4241 }
4242
4243 void ManualMapVoxelManipulator::blitBackAll(
4244                 std::map<v3s16, MapBlock*> * modified_blocks)
4245 {
4246         if(m_area.getExtent() == v3s16(0,0,0))
4247                 return;
4248
4249         /*
4250                 Copy data of all blocks
4251         */
4252         for(std::map<v3s16, u8>::iterator
4253                         i = m_loaded_blocks.begin();
4254                         i != m_loaded_blocks.end(); ++i)
4255         {
4256                 v3s16 p = i->first;
4257                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
4258                 bool existed = !(i->second & VMANIP_BLOCK_DATA_INEXIST);
4259                 if(existed == false)
4260                 {
4261                         continue;
4262                 }
4263
4264                 block->copyFrom(*this);
4265
4266                 if(modified_blocks)
4267                         (*modified_blocks)[p] = block;
4268         }
4269 }
4270
4271 //END