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