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