Merge remote branch 'origin/master'
[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 };
1617
1618 void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
1619 {
1620         INodeDefManager *nodemgr = m_gamedef->ndef();
1621
1622         DSTACK(__FUNCTION_NAME);
1623         //TimeTaker timer("transformLiquids()");
1624
1625         u32 loopcount = 0;
1626         u32 initial_size = m_transforming_liquid.size();
1627
1628         /*if(initial_size != 0)
1629                 infostream<<"transformLiquids(): initial_size="<<initial_size<<std::endl;*/
1630
1631         // list of nodes that due to viscosity have not reached their max level height
1632         UniqueQueue<v3s16> must_reflow;
1633
1634         // List of MapBlocks that will require a lighting update (due to lava)
1635         core::map<v3s16, MapBlock*> lighting_modified_blocks;
1636
1637         while(m_transforming_liquid.size() != 0)
1638         {
1639                 // This should be done here so that it is done when continue is used
1640                 if(loopcount >= initial_size || loopcount >= 10000)
1641                         break;
1642                 loopcount++;
1643
1644                 /*
1645                         Get a queued transforming liquid node
1646                 */
1647                 v3s16 p0 = m_transforming_liquid.pop_front();
1648
1649                 MapNode n0 = getNodeNoEx(p0);
1650
1651                 /*
1652                         Collect information about current node
1653                  */
1654                 s8 liquid_level = -1;
1655                 content_t liquid_kind = CONTENT_IGNORE;
1656                 LiquidType liquid_type = nodemgr->get(n0).liquid_type;
1657                 switch (liquid_type) {
1658                         case LIQUID_SOURCE:
1659                                 liquid_level = LIQUID_LEVEL_SOURCE;
1660                                 liquid_kind = nodemgr->getId(nodemgr->get(n0).liquid_alternative_flowing);
1661                                 break;
1662                         case LIQUID_FLOWING:
1663                                 liquid_level = (n0.param2 & LIQUID_LEVEL_MASK);
1664                                 liquid_kind = n0.getContent();
1665                                 break;
1666                         case LIQUID_NONE:
1667                                 // if this is an air node, it *could* be transformed into a liquid. otherwise,
1668                                 // continue with the next node.
1669                                 if (n0.getContent() != CONTENT_AIR)
1670                                         continue;
1671                                 liquid_kind = CONTENT_AIR;
1672                                 break;
1673                 }
1674
1675                 /*
1676                         Collect information about the environment
1677                  */
1678                 const v3s16 *dirs = g_6dirs;
1679                 NodeNeighbor sources[6]; // surrounding sources
1680                 int num_sources = 0;
1681                 NodeNeighbor flows[6]; // surrounding flowing liquid nodes
1682                 int num_flows = 0;
1683                 NodeNeighbor airs[6]; // surrounding air
1684                 int num_airs = 0;
1685                 NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid
1686                 int num_neutrals = 0;
1687                 bool flowing_down = false;
1688                 for (u16 i = 0; i < 6; i++) {
1689                         NeighborType nt = NEIGHBOR_SAME_LEVEL;
1690                         switch (i) {
1691                                 case 1:
1692                                         nt = NEIGHBOR_UPPER;
1693                                         break;
1694                                 case 4:
1695                                         nt = NEIGHBOR_LOWER;
1696                                         break;
1697                         }
1698                         v3s16 npos = p0 + dirs[i];
1699                         NodeNeighbor nb = {getNodeNoEx(npos), nt, npos};
1700                         switch (nodemgr->get(nb.n.getContent()).liquid_type) {
1701                                 case LIQUID_NONE:
1702                                         if (nb.n.getContent() == CONTENT_AIR) {
1703                                                 airs[num_airs++] = nb;
1704                                                 // if the current node is a water source the neighbor
1705                                                 // should be enqueded for transformation regardless of whether the
1706                                                 // current node changes or not.
1707                                                 if (nb.t != NEIGHBOR_UPPER && liquid_type != LIQUID_NONE)
1708                                                         m_transforming_liquid.push_back(npos);
1709                                                 // if the current node happens to be a flowing node, it will start to flow down here.
1710                                                 if (nb.t == NEIGHBOR_LOWER) {
1711                                                         flowing_down = true;
1712                                                 }
1713                                         } else {
1714                                                 neutrals[num_neutrals++] = nb;
1715                                         }
1716                                         break;
1717                                 case LIQUID_SOURCE:
1718                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1719                                         if (liquid_kind == CONTENT_AIR)
1720                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1721                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1722                                                 neutrals[num_neutrals++] = nb;
1723                                         } else {
1724                                                 // Do not count bottom source, it will screw things up
1725                                                 if(dirs[i].Y != -1)
1726                                                         sources[num_sources++] = nb;
1727                                         }
1728                                         break;
1729                                 case LIQUID_FLOWING:
1730                                         // if this node is not (yet) of a liquid type, choose the first liquid type we encounter
1731                                         if (liquid_kind == CONTENT_AIR)
1732                                                 liquid_kind = nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing);
1733                                         if (nodemgr->getId(nodemgr->get(nb.n).liquid_alternative_flowing) != liquid_kind) {
1734                                                 neutrals[num_neutrals++] = nb;
1735                                         } else {
1736                                                 flows[num_flows++] = nb;
1737                                                 if (nb.t == NEIGHBOR_LOWER)
1738                                                         flowing_down = true;
1739                                         }
1740                                         break;
1741                         }
1742                 }
1743
1744                 /*
1745                         decide on the type (and possibly level) of the current node
1746                  */
1747                 content_t new_node_content;
1748                 s8 new_node_level = -1;
1749                 s8 max_node_level = -1;
1750                 if ((num_sources >= 2 && nodemgr->get(liquid_kind).liquid_renewable) || liquid_type == LIQUID_SOURCE) {
1751                         // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid)
1752                         // or the flowing alternative of the first of the surrounding sources (if it's air), so
1753                         // it's perfectly safe to use liquid_kind here to determine the new node content.
1754                         new_node_content = nodemgr->getId(nodemgr->get(liquid_kind).liquid_alternative_source);
1755                 } else if (num_sources >= 1 && sources[0].t != NEIGHBOR_LOWER) {
1756                         // liquid_kind is set properly, see above
1757                         new_node_content = liquid_kind;
1758                         max_node_level = new_node_level = LIQUID_LEVEL_MAX;
1759                 } else {
1760                         // no surrounding sources, so get the maximum level that can flow into this node
1761                         for (u16 i = 0; i < num_flows; i++) {
1762                                 u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK);
1763                                 switch (flows[i].t) {
1764                                         case NEIGHBOR_UPPER:
1765                                                 if (nb_liquid_level + WATER_DROP_BOOST > max_node_level) {
1766                                                         max_node_level = LIQUID_LEVEL_MAX;
1767                                                         if (nb_liquid_level + WATER_DROP_BOOST < LIQUID_LEVEL_MAX)
1768                                                                 max_node_level = nb_liquid_level + WATER_DROP_BOOST;
1769                                                 } else if (nb_liquid_level > max_node_level)
1770                                                         max_node_level = nb_liquid_level;
1771                                                 break;
1772                                         case NEIGHBOR_LOWER:
1773                                                 break;
1774                                         case NEIGHBOR_SAME_LEVEL:
1775                                                 if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK &&
1776                                                         nb_liquid_level > 0 && nb_liquid_level - 1 > max_node_level) {
1777                                                         max_node_level = nb_liquid_level - 1;
1778                                                 }
1779                                                 break;
1780                                 }
1781                         }
1782
1783                         u8 viscosity = nodemgr->get(liquid_kind).liquid_viscosity;
1784                         if (viscosity > 1 && max_node_level != liquid_level) {
1785                                 // amount to gain, limited by viscosity
1786                                 // must be at least 1 in absolute value
1787                                 s8 level_inc = max_node_level - liquid_level;
1788                                 if (level_inc < -viscosity || level_inc > viscosity)
1789                                         new_node_level = liquid_level + level_inc/viscosity;
1790                                 else if (level_inc < 0)
1791                                         new_node_level = liquid_level - 1;
1792                                 else if (level_inc > 0)
1793                                         new_node_level = liquid_level + 1;
1794                                 if (new_node_level != max_node_level)
1795                                         must_reflow.push_back(p0);
1796                         } else
1797                                 new_node_level = max_node_level;
1798
1799                         if (new_node_level >= 0)
1800                                 new_node_content = liquid_kind;
1801                         else
1802                                 new_node_content = CONTENT_AIR;
1803
1804                 }
1805
1806                 /*
1807                         check if anything has changed. if not, just continue with the next node.
1808                  */
1809                 if (new_node_content == n0.getContent() && (nodemgr->get(n0.getContent()).liquid_type != LIQUID_FLOWING ||
1810                                                                                  ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level &&
1811                                                                                  ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK)
1812                                                                                  == flowing_down)))
1813                         continue;
1814
1815
1816                 /*
1817                         update the current node
1818                  */
1819                 //bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK));
1820                 if (nodemgr->get(new_node_content).liquid_type == LIQUID_FLOWING) {
1821                         // set level to last 3 bits, flowing down bit to 4th bit
1822                         n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK);
1823                 } else {
1824                         // set the liquid level and flow bit to 0
1825                         n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK);
1826                 }
1827                 n0.setContent(new_node_content);
1828
1829                 // Find out whether there is a suspect for this action
1830                 std::string suspect;
1831                 if(m_gamedef->rollback()){
1832                         suspect = m_gamedef->rollback()->getSuspect(p0, 83, 1);
1833                 }
1834
1835                 if(!suspect.empty()){
1836                         // Blame suspect
1837                         RollbackScopeActor rollback_scope(m_gamedef->rollback(), suspect, true);
1838                         // Get old node for rollback
1839                         RollbackNode rollback_oldnode(this, p0, m_gamedef);
1840                         // Set node
1841                         setNode(p0, n0);
1842                         // Report
1843                         RollbackNode rollback_newnode(this, p0, m_gamedef);
1844                         RollbackAction action;
1845                         action.setSetNode(p0, rollback_oldnode, rollback_newnode);
1846                         m_gamedef->rollback()->reportAction(action);
1847                 } else {
1848                         // Set node
1849                         setNode(p0, n0);
1850                 }
1851
1852                 v3s16 blockpos = getNodeBlockPos(p0);
1853                 MapBlock *block = getBlockNoCreateNoEx(blockpos);
1854                 if(block != NULL) {
1855                         modified_blocks.insert(blockpos, block);
1856                         // If node emits light, MapBlock requires lighting update
1857                         if(nodemgr->get(n0).light_source != 0)
1858                                 lighting_modified_blocks[block->getPos()] = block;
1859                 }
1860
1861                 /*
1862                         enqueue neighbors for update if neccessary
1863                  */
1864                 switch (nodemgr->get(n0.getContent()).liquid_type) {
1865                         case LIQUID_SOURCE:
1866                         case LIQUID_FLOWING:
1867                                 // make sure source flows into all neighboring nodes
1868                                 for (u16 i = 0; i < num_flows; i++)
1869                                         if (flows[i].t != NEIGHBOR_UPPER)
1870                                                 m_transforming_liquid.push_back(flows[i].p);
1871                                 for (u16 i = 0; i < num_airs; i++)
1872                                         if (airs[i].t != NEIGHBOR_UPPER)
1873                                                 m_transforming_liquid.push_back(airs[i].p);
1874                                 break;
1875                         case LIQUID_NONE:
1876                                 // this flow has turned to air; neighboring flows might need to do the same
1877                                 for (u16 i = 0; i < num_flows; i++)
1878                                         m_transforming_liquid.push_back(flows[i].p);
1879                                 break;
1880                 }
1881         }
1882         //infostream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl;
1883         while (must_reflow.size() > 0)
1884                 m_transforming_liquid.push_back(must_reflow.pop_front());
1885         updateLighting(lighting_modified_blocks, modified_blocks);
1886 }
1887
1888 NodeMetadata* Map::getNodeMetadata(v3s16 p)
1889 {
1890         v3s16 blockpos = getNodeBlockPos(p);
1891         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1892         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1893         if(!block){
1894                 infostream<<"Map::getNodeMetadata(): Need to emerge "
1895                                 <<PP(blockpos)<<std::endl;
1896                 block = emergeBlock(blockpos, false);
1897         }
1898         if(!block)
1899         {
1900                 infostream<<"WARNING: Map::getNodeMetadata(): Block not found"
1901                                 <<std::endl;
1902                 return NULL;
1903         }
1904         NodeMetadata *meta = block->m_node_metadata.get(p_rel);
1905         return meta;
1906 }
1907
1908 void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta)
1909 {
1910         v3s16 blockpos = getNodeBlockPos(p);
1911         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1912         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1913         if(!block){
1914                 infostream<<"Map::setNodeMetadata(): Need to emerge "
1915                                 <<PP(blockpos)<<std::endl;
1916                 block = emergeBlock(blockpos, false);
1917         }
1918         if(!block)
1919         {
1920                 infostream<<"WARNING: Map::setNodeMetadata(): Block not found"
1921                                 <<std::endl;
1922                 return;
1923         }
1924         block->m_node_metadata.set(p_rel, meta);
1925 }
1926
1927 void Map::removeNodeMetadata(v3s16 p)
1928 {
1929         v3s16 blockpos = getNodeBlockPos(p);
1930         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1931         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1932         if(block == NULL)
1933         {
1934                 infostream<<"WARNING: Map::removeNodeMetadata(): Block not found"
1935                                 <<std::endl;
1936                 return;
1937         }
1938         block->m_node_metadata.remove(p_rel);
1939 }
1940
1941 NodeTimer Map::getNodeTimer(v3s16 p)
1942 {
1943         v3s16 blockpos = getNodeBlockPos(p);
1944         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1945         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1946         if(!block){
1947                 infostream<<"Map::getNodeTimer(): Need to emerge "
1948                                 <<PP(blockpos)<<std::endl;
1949                 block = emergeBlock(blockpos, false);
1950         }
1951         if(!block)
1952         {
1953                 infostream<<"WARNING: Map::getNodeTimer(): Block not found"
1954                                 <<std::endl;
1955                 return NodeTimer();
1956         }
1957         NodeTimer t = block->m_node_timers.get(p_rel);
1958         return t;
1959 }
1960
1961 void Map::setNodeTimer(v3s16 p, NodeTimer t)
1962 {
1963         v3s16 blockpos = getNodeBlockPos(p);
1964         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1965         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1966         if(!block){
1967                 infostream<<"Map::setNodeTimer(): Need to emerge "
1968                                 <<PP(blockpos)<<std::endl;
1969                 block = emergeBlock(blockpos, false);
1970         }
1971         if(!block)
1972         {
1973                 infostream<<"WARNING: Map::setNodeTimer(): Block not found"
1974                                 <<std::endl;
1975                 return;
1976         }
1977         block->m_node_timers.set(p_rel, t);
1978 }
1979
1980 void Map::removeNodeTimer(v3s16 p)
1981 {
1982         v3s16 blockpos = getNodeBlockPos(p);
1983         v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE;
1984         MapBlock *block = getBlockNoCreateNoEx(blockpos);
1985         if(block == NULL)
1986         {
1987                 infostream<<"WARNING: Map::removeNodeTimer(): Block not found"
1988                                 <<std::endl;
1989                 return;
1990         }
1991         block->m_node_timers.remove(p_rel);
1992 }
1993
1994 /*
1995         ServerMap
1996 */
1997 ServerMap::ServerMap(std::string savedir, IGameDef *gamedef, EmergeManager *emerge):
1998         Map(dout_server, gamedef),
1999         m_seed(0),
2000         m_map_metadata_changed(true),
2001         m_database(NULL),
2002         m_database_read(NULL),
2003         m_database_write(NULL)
2004 {
2005         verbosestream<<__FUNCTION_NAME<<std::endl;
2006
2007         m_emerge = emerge;
2008         m_mgparams = m_emerge->getParamsFromSettings(g_settings);
2009         if (!m_mgparams)
2010                 m_mgparams = new MapgenV6Params();
2011                 
2012         m_seed = m_mgparams->seed;
2013
2014         if (g_settings->get("fixed_map_seed").empty())
2015         {
2016                 m_seed = (((u64)(myrand() & 0xffff) << 0)
2017                                 | ((u64)(myrand() & 0xffff) << 16)
2018                                 | ((u64)(myrand() & 0xffff) << 32)
2019                                 | ((u64)(myrand() & 0xffff) << 48));
2020                 m_mgparams->seed = m_seed;
2021         }
2022
2023         /*
2024                 Experimental and debug stuff
2025         */
2026
2027         {
2028         }
2029
2030         /*
2031                 Try to load map; if not found, create a new one.
2032         */
2033
2034         m_savedir = savedir;
2035         m_map_saving_enabled = false;
2036
2037         try
2038         {
2039                 // If directory exists, check contents and load if possible
2040                 if(fs::PathExists(m_savedir))
2041                 {
2042                         // If directory is empty, it is safe to save into it.
2043                         if(fs::GetDirListing(m_savedir).size() == 0)
2044                         {
2045                                 infostream<<"ServerMap: Empty save directory is valid."
2046                                                 <<std::endl;
2047                                 m_map_saving_enabled = true;
2048                         }
2049                         else
2050                         {
2051                                 try{
2052                                         // Load map metadata (seed, chunksize)
2053                                         loadMapMeta();
2054                                 }
2055                                 catch(SettingNotFoundException &e){
2056                                         infostream<<"ServerMap:  Some metadata not found."
2057                                                           <<" Using default settings."<<std::endl;
2058                                 }
2059                                 catch(FileNotGoodException &e){
2060                                         infostream<<"WARNING: Could not load map metadata"
2061                                                         //<<" Disabling chunk-based generator."
2062                                                         <<std::endl;
2063                                         //m_chunksize = 0;
2064                                 }
2065
2066                                 infostream<<"ServerMap: Successfully loaded map "
2067                                                 <<"metadata from "<<savedir
2068                                                 <<", assuming valid save directory."
2069                                                 <<" seed="<<m_seed<<"."
2070                                                 <<std::endl;
2071
2072                                 m_map_saving_enabled = true;
2073                                 // Map loaded, not creating new one
2074                                 return;
2075                         }
2076                 }
2077                 // If directory doesn't exist, it is safe to save to it
2078                 else{
2079                         m_map_saving_enabled = true;
2080                 }
2081         }
2082         catch(std::exception &e)
2083         {
2084                 infostream<<"WARNING: ServerMap: Failed to load map from "<<savedir
2085                                 <<", exception: "<<e.what()<<std::endl;
2086                 infostream<<"Please remove the map or fix it."<<std::endl;
2087                 infostream<<"WARNING: Map saving will be disabled."<<std::endl;
2088         }
2089
2090         infostream<<"Initializing new map."<<std::endl;
2091
2092         // Create zero sector
2093         emergeSector(v2s16(0,0));
2094
2095         // Initially write whole map
2096         save(MOD_STATE_CLEAN);
2097 }
2098
2099 ServerMap::~ServerMap()
2100 {
2101         verbosestream<<__FUNCTION_NAME<<std::endl;
2102
2103         try
2104         {
2105                 if(m_map_saving_enabled)
2106                 {
2107                         // Save only changed parts
2108                         save(MOD_STATE_WRITE_AT_UNLOAD);
2109                         infostream<<"ServerMap: Saved map to "<<m_savedir<<std::endl;
2110                 }
2111                 else
2112                 {
2113                         infostream<<"ServerMap: Map not saved"<<std::endl;
2114                 }
2115         }
2116         catch(std::exception &e)
2117         {
2118                 infostream<<"ServerMap: Failed to save map to "<<m_savedir
2119                                 <<", exception: "<<e.what()<<std::endl;
2120         }
2121
2122         /*
2123                 Close database if it was opened
2124         */
2125         if(m_database_read)
2126                 sqlite3_finalize(m_database_read);
2127         if(m_database_write)
2128                 sqlite3_finalize(m_database_write);
2129         if(m_database)
2130                 sqlite3_close(m_database);
2131
2132 #if 0
2133         /*
2134                 Free all MapChunks
2135         */
2136         core::map<v2s16, MapChunk*>::Iterator i = m_chunks.getIterator();
2137         for(; i.atEnd() == false; i++)
2138         {
2139                 MapChunk *chunk = i.getNode()->getValue();
2140                 delete chunk;
2141         }
2142 #endif
2143 }
2144
2145 void ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
2146 {
2147         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2148         if(enable_mapgen_debug_info)
2149                 infostream<<"initBlockMake(): "
2150                                 <<"("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<") - "
2151                                 <<"("<<blockpos.X<<","<<blockpos.Y<<","<<blockpos.Z<<")"
2152                                 <<std::endl;
2153
2154         //s16 chunksize = 3;
2155         //v3s16 chunk_offset(-1,-1,-1);
2156         //s16 chunksize = 4;
2157         //v3s16 chunk_offset(-1,-1,-1);
2158         s16 chunksize = 5;
2159         v3s16 chunk_offset(-2,-2,-2);
2160         v3s16 blockpos_div = getContainerPos(blockpos - chunk_offset, chunksize);
2161         v3s16 blockpos_min = blockpos_div * chunksize;
2162         v3s16 blockpos_max = blockpos_div * chunksize + v3s16(1,1,1)*(chunksize-1);
2163         blockpos_min += chunk_offset;
2164         blockpos_max += chunk_offset;
2165
2166         //v3s16 extra_borders(1,1,1);
2167         v3s16 extra_borders(1,1,1);
2168
2169         // Do nothing if not inside limits (+-1 because of neighbors)
2170         if(blockpos_over_limit(blockpos_min - extra_borders) ||
2171                 blockpos_over_limit(blockpos_max + extra_borders))
2172         {
2173                 data->no_op = true;
2174                 return;
2175         }
2176
2177         data->no_op = false;
2178         data->seed = m_seed;
2179         data->blockpos_min = blockpos_min;
2180         data->blockpos_max = blockpos_max;
2181         data->blockpos_requested = blockpos;
2182         data->nodedef = m_gamedef->ndef();
2183
2184         /*
2185                 Create the whole area of this and the neighboring blocks
2186         */
2187         {
2188                 //TimeTaker timer("initBlockMake() create area");
2189
2190                 for(s16 x=blockpos_min.X-extra_borders.X;
2191                                 x<=blockpos_max.X+extra_borders.X; x++)
2192                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2193                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2194                 {
2195                         v2s16 sectorpos(x, z);
2196                         // Sector metadata is loaded from disk if not already loaded.
2197                         ServerMapSector *sector = createSector(sectorpos);
2198                         assert(sector);
2199
2200                         for(s16 y=blockpos_min.Y-extra_borders.Y;
2201                                         y<=blockpos_max.Y+extra_borders.Y; y++)
2202                         {
2203                                 v3s16 p(x,y,z);
2204                                 //MapBlock *block = createBlock(p);
2205                                 // 1) get from memory, 2) load from disk
2206                                 MapBlock *block = emergeBlock(p, false);
2207                                 // 3) create a blank one
2208                                 if(block == NULL)
2209                                 {
2210                                         block = createBlock(p);
2211
2212                                         /*
2213                                                 Block gets sunlight if this is true.
2214
2215                                                 Refer to the map generator heuristics.
2216                                         */
2217                                         bool ug = m_emerge->isBlockUnderground(p);
2218                                         block->setIsUnderground(ug);
2219                                 }
2220
2221                                 // Lighting will not be valid after make_chunk is called
2222                                 block->setLightingExpired(true);
2223                                 // Lighting will be calculated
2224                                 //block->setLightingExpired(false);
2225                         }
2226                 }
2227         }
2228
2229         /*
2230                 Now we have a big empty area.
2231
2232                 Make a ManualMapVoxelManipulator that contains this and the
2233                 neighboring blocks
2234         */
2235
2236         // The area that contains this block and it's neighbors
2237         v3s16 bigarea_blocks_min = blockpos_min - extra_borders;
2238         v3s16 bigarea_blocks_max = blockpos_max + extra_borders;
2239
2240         data->vmanip = new ManualMapVoxelManipulator(this);
2241         //data->vmanip->setMap(this);
2242
2243         // Add the area
2244         {
2245                 //TimeTaker timer("initBlockMake() initialEmerge");
2246                 data->vmanip->initialEmerge(bigarea_blocks_min, bigarea_blocks_max);
2247         }
2248
2249         // Data is ready now.
2250 }
2251
2252 MapBlock* ServerMap::finishBlockMake(BlockMakeData *data,
2253                 core::map<v3s16, MapBlock*> &changed_blocks)
2254 {
2255         v3s16 blockpos_min = data->blockpos_min;
2256         v3s16 blockpos_max = data->blockpos_max;
2257         v3s16 blockpos_requested = data->blockpos_requested;
2258         /*infostream<<"finishBlockMake(): ("<<blockpos_requested.X<<","
2259                         <<blockpos_requested.Y<<","
2260                         <<blockpos_requested.Z<<")"<<std::endl;*/
2261
2262         v3s16 extra_borders(1,1,1);
2263
2264         if(data->no_op)
2265         {
2266                 //infostream<<"finishBlockMake(): no-op"<<std::endl;
2267                 return NULL;
2268         }
2269
2270         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2271
2272         /*infostream<<"Resulting vmanip:"<<std::endl;
2273         data->vmanip.print(infostream);*/
2274
2275         // Make sure affected blocks are loaded
2276         for(s16 x=blockpos_min.X-extra_borders.X;
2277                         x<=blockpos_max.X+extra_borders.X; x++)
2278         for(s16 z=blockpos_min.Z-extra_borders.Z;
2279                         z<=blockpos_max.Z+extra_borders.Z; z++)
2280         for(s16 y=blockpos_min.Y-extra_borders.Y;
2281                         y<=blockpos_max.Y+extra_borders.Y; y++)
2282         {
2283                 v3s16 p(x, y, z);
2284                 // Load from disk if not already in memory
2285                 emergeBlock(p, false);
2286         }
2287
2288         /*
2289                 Blit generated stuff to map
2290                 NOTE: blitBackAll adds nearly everything to changed_blocks
2291         */
2292         {
2293                 // 70ms @cs=8
2294                 //TimeTaker timer("finishBlockMake() blitBackAll");
2295                 data->vmanip->blitBackAll(&changed_blocks);
2296         }
2297
2298         if(enable_mapgen_debug_info)
2299                 infostream<<"finishBlockMake: changed_blocks.size()="
2300                                 <<changed_blocks.size()<<std::endl;
2301
2302         /*
2303                 Copy transforming liquid information
2304         */
2305         while(data->transforming_liquid.size() > 0)
2306         {
2307                 v3s16 p = data->transforming_liquid.pop_front();
2308                 m_transforming_liquid.push_back(p);
2309         }
2310
2311         /*
2312                 Do stuff in central blocks
2313         */
2314
2315         /*
2316                 Update lighting
2317         */
2318         {
2319 #if 0
2320                 TimeTaker t("finishBlockMake lighting update");
2321
2322                 core::map<v3s16, MapBlock*> lighting_update_blocks;
2323
2324                 // Center blocks
2325                 for(s16 x=blockpos_min.X-extra_borders.X;
2326                                 x<=blockpos_max.X+extra_borders.X; x++)
2327                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2328                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2329                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2330                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2331                 {
2332                         v3s16 p(x, y, z);
2333                         MapBlock *block = getBlockNoCreateNoEx(p);
2334                         assert(block);
2335                         lighting_update_blocks.insert(block->getPos(), block);
2336                 }
2337
2338                 updateLighting(lighting_update_blocks, changed_blocks);
2339 #endif
2340
2341                 /*
2342                         Set lighting to non-expired state in all of them.
2343                         This is cheating, but it is not fast enough if all of them
2344                         would actually be updated.
2345                 */
2346                 for(s16 x=blockpos_min.X-extra_borders.X;
2347                                 x<=blockpos_max.X+extra_borders.X; x++)
2348                 for(s16 z=blockpos_min.Z-extra_borders.Z;
2349                                 z<=blockpos_max.Z+extra_borders.Z; z++)
2350                 for(s16 y=blockpos_min.Y-extra_borders.Y;
2351                                 y<=blockpos_max.Y+extra_borders.Y; y++)
2352                 {
2353                         v3s16 p(x, y, z);
2354                         getBlockNoCreateNoEx(p)->setLightingExpired(false);
2355                 }
2356
2357 #if 0
2358                 if(enable_mapgen_debug_info == false)
2359                         t.stop(true); // Hide output
2360 #endif
2361         }
2362
2363         /*
2364                 Go through changed blocks
2365         */
2366         for(core::map<v3s16, MapBlock*>::Iterator i = changed_blocks.getIterator();
2367                         i.atEnd() == false; i++)
2368         {
2369                 MapBlock *block = i.getNode()->getValue();
2370                 assert(block);
2371                 /*
2372                         Update day/night difference cache of the MapBlocks
2373                 */
2374                 block->expireDayNightDiff();
2375                 /*
2376                         Set block as modified
2377                 */
2378                 block->raiseModified(MOD_STATE_WRITE_NEEDED,
2379                                 "finishBlockMake expireDayNightDiff");
2380         }
2381
2382         /*
2383                 Set central blocks as generated
2384         */
2385         for(s16 x=blockpos_min.X; x<=blockpos_max.X; x++)
2386         for(s16 z=blockpos_min.Z; z<=blockpos_max.Z; z++)
2387         for(s16 y=blockpos_min.Y; y<=blockpos_max.Y; y++)
2388         {
2389                 v3s16 p(x, y, z);
2390                 MapBlock *block = getBlockNoCreateNoEx(p);
2391                 assert(block);
2392                 block->setGenerated(true);
2393         }
2394
2395         /*
2396                 Save changed parts of map
2397                 NOTE: Will be saved later.
2398         */
2399         //save(MOD_STATE_WRITE_AT_UNLOAD);
2400
2401         /*infostream<<"finishBlockMake() done for ("<<blockpos_requested.X
2402                         <<","<<blockpos_requested.Y<<","
2403                         <<blockpos_requested.Z<<")"<<std::endl;*/
2404 #if 0
2405         if(enable_mapgen_debug_info)
2406         {
2407                 /*
2408                         Analyze resulting blocks
2409                 */
2410                 /*for(s16 x=blockpos_min.X-1; x<=blockpos_max.X+1; x++)
2411                 for(s16 z=blockpos_min.Z-1; z<=blockpos_max.Z+1; z++)
2412                 for(s16 y=blockpos_min.Y-1; y<=blockpos_max.Y+1; y++)*/
2413                 for(s16 x=blockpos_min.X-0; x<=blockpos_max.X+0; x++)
2414                 for(s16 z=blockpos_min.Z-0; z<=blockpos_max.Z+0; z++)
2415                 for(s16 y=blockpos_min.Y-0; y<=blockpos_max.Y+0; y++)
2416                 {
2417                         v3s16 p = v3s16(x,y,z);
2418                         MapBlock *block = getBlockNoCreateNoEx(p);
2419                         char spos[20];
2420                         snprintf(spos, 20, "(%2d,%2d,%2d)", x, y, z);
2421                         infostream<<"Generated "<<spos<<": "
2422                                         <<analyze_block(block)<<std::endl;
2423                 }
2424         }
2425 #endif
2426
2427         MapBlock *block = getBlockNoCreateNoEx(blockpos_requested);
2428         assert(block);
2429
2430         return block;
2431 }
2432
2433 ServerMapSector * ServerMap::createSector(v2s16 p2d)
2434 {
2435         DSTACKF("%s: p2d=(%d,%d)",
2436                         __FUNCTION_NAME,
2437                         p2d.X, p2d.Y);
2438
2439         /*
2440                 Check if it exists already in memory
2441         */
2442         ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2443         if(sector != NULL)
2444                 return sector;
2445
2446         /*
2447                 Try to load it from disk (with blocks)
2448         */
2449         //if(loadSectorFull(p2d) == true)
2450
2451         /*
2452                 Try to load metadata from disk
2453         */
2454 #if 0
2455         if(loadSectorMeta(p2d) == true)
2456         {
2457                 ServerMapSector *sector = (ServerMapSector*)getSectorNoGenerateNoEx(p2d);
2458                 if(sector == NULL)
2459                 {
2460                         infostream<<"ServerMap::createSector(): loadSectorFull didn't make a sector"<<std::endl;
2461                         throw InvalidPositionException("");
2462                 }
2463                 return sector;
2464         }
2465 #endif
2466         /*
2467                 Do not create over-limit
2468         */
2469         if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2470         || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2471         || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2472         || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2473                 throw InvalidPositionException("createSector(): pos. over limit");
2474
2475         /*
2476                 Generate blank sector
2477         */
2478
2479         sector = new ServerMapSector(this, p2d, m_gamedef);
2480
2481         // Sector position on map in nodes
2482         v2s16 nodepos2d = p2d * MAP_BLOCKSIZE;
2483
2484         /*
2485                 Insert to container
2486         */
2487         m_sectors.insert(p2d, sector);
2488
2489         return sector;
2490 }
2491
2492 #if 0
2493 /*
2494         This is a quick-hand function for calling makeBlock().
2495 */
2496 MapBlock * ServerMap::generateBlock(
2497                 v3s16 p,
2498                 core::map<v3s16, MapBlock*> &modified_blocks
2499 )
2500 {
2501         DSTACKF("%s: p=(%d,%d,%d)", __FUNCTION_NAME, p.X, p.Y, p.Z);
2502
2503         /*infostream<<"generateBlock(): "
2504                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2505                         <<std::endl;*/
2506
2507         bool enable_mapgen_debug_info = g_settings->getBool("enable_mapgen_debug_info");
2508
2509         TimeTaker timer("generateBlock");
2510
2511         //MapBlock *block = original_dummy;
2512
2513         v2s16 p2d(p.X, p.Z);
2514         v2s16 p2d_nodes = p2d * MAP_BLOCKSIZE;
2515
2516         /*
2517                 Do not generate over-limit
2518         */
2519         if(blockpos_over_limit(p))
2520         {
2521                 infostream<<__FUNCTION_NAME<<": Block position over limit"<<std::endl;
2522                 throw InvalidPositionException("generateBlock(): pos. over limit");
2523         }
2524
2525         /*
2526                 Create block make data
2527         */
2528         BlockMakeData data;
2529         initBlockMake(&data, p);
2530
2531         /*
2532                 Generate block
2533         */
2534         {
2535                 TimeTaker t("mapgen::make_block()");
2536                 mapgen->makeChunk(&data);
2537                 //mapgen::make_block(&data);
2538
2539                 if(enable_mapgen_debug_info == false)
2540                         t.stop(true); // Hide output
2541         }
2542
2543         /*
2544                 Blit data back on map, update lighting, add mobs and whatever this does
2545         */
2546         finishBlockMake(&data, modified_blocks);
2547
2548         /*
2549                 Get central block
2550         */
2551         MapBlock *block = getBlockNoCreateNoEx(p);
2552
2553 #if 0
2554         /*
2555                 Check result
2556         */
2557         if(block)
2558         {
2559                 bool erroneus_content = false;
2560                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2561                 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2562                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2563                 {
2564                         v3s16 p(x0,y0,z0);
2565                         MapNode n = block->getNode(p);
2566                         if(n.getContent() == CONTENT_IGNORE)
2567                         {
2568                                 infostream<<"CONTENT_IGNORE at "
2569                                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
2570                                                 <<std::endl;
2571                                 erroneus_content = true;
2572                                 assert(0);
2573                         }
2574                 }
2575                 if(erroneus_content)
2576                 {
2577                         assert(0);
2578                 }
2579         }
2580 #endif
2581
2582 #if 0
2583         /*
2584                 Generate a completely empty block
2585         */
2586         if(block)
2587         {
2588                 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
2589                 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
2590                 {
2591                         for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
2592                         {
2593                                 MapNode n;
2594                                 n.setContent(CONTENT_AIR);
2595                                 block->setNode(v3s16(x0,y0,z0), n);
2596                         }
2597                 }
2598         }
2599 #endif
2600
2601         if(enable_mapgen_debug_info == false)
2602                 timer.stop(true); // Hide output
2603
2604         return block;
2605 }
2606 #endif
2607
2608 MapBlock * ServerMap::createBlock(v3s16 p)
2609 {
2610         DSTACKF("%s: p=(%d,%d,%d)",
2611                         __FUNCTION_NAME, p.X, p.Y, p.Z);
2612
2613         /*
2614                 Do not create over-limit
2615         */
2616         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2617         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2618         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2619         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2620         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
2621         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
2622                 throw InvalidPositionException("createBlock(): pos. over limit");
2623
2624         v2s16 p2d(p.X, p.Z);
2625         s16 block_y = p.Y;
2626         /*
2627                 This will create or load a sector if not found in memory.
2628                 If block exists on disk, it will be loaded.
2629
2630                 NOTE: On old save formats, this will be slow, as it generates
2631                       lighting on blocks for them.
2632         */
2633         ServerMapSector *sector;
2634         try{
2635                 sector = (ServerMapSector*)createSector(p2d);
2636                 assert(sector->getId() == MAPSECTOR_SERVER);
2637         }
2638         catch(InvalidPositionException &e)
2639         {
2640                 infostream<<"createBlock: createSector() failed"<<std::endl;
2641                 throw e;
2642         }
2643         /*
2644                 NOTE: This should not be done, or at least the exception
2645                 should not be passed on as std::exception, because it
2646                 won't be catched at all.
2647         */
2648         /*catch(std::exception &e)
2649         {
2650                 infostream<<"createBlock: createSector() failed: "
2651                                 <<e.what()<<std::endl;
2652                 throw e;
2653         }*/
2654
2655         /*
2656                 Try to get a block from the sector
2657         */
2658
2659         MapBlock *block = sector->getBlockNoCreateNoEx(block_y);
2660         if(block)
2661         {
2662                 if(block->isDummy())
2663                         block->unDummify();
2664                 return block;
2665         }
2666         // Create blank
2667         block = sector->createBlankBlock(block_y);
2668
2669         return block;
2670 }
2671
2672 MapBlock * ServerMap::emergeBlock(v3s16 p, bool create_blank)
2673 {
2674         DSTACKF("%s: p=(%d,%d,%d), create_blank=%d",
2675                         __FUNCTION_NAME,
2676                         p.X, p.Y, p.Z, create_blank);
2677
2678         {
2679                 MapBlock *block = getBlockNoCreateNoEx(p);
2680                 if(block && block->isDummy() == false)
2681                         return block;
2682         }
2683
2684         {
2685                 MapBlock *block = loadBlock(p);
2686                 if(block)
2687                         return block;
2688         }
2689
2690         if (create_blank) {
2691                 ServerMapSector *sector = createSector(v2s16(p.X, p.Z));
2692                 MapBlock *block = sector->createBlankBlock(p.Y);
2693
2694                 return block;
2695         }
2696         /*if(allow_generate)
2697         {
2698                 core::map<v3s16, MapBlock*> modified_blocks;
2699                 MapBlock *block = generateBlock(p, modified_blocks);
2700                 if(block)
2701                 {
2702                         MapEditEvent event;
2703                         event.type = MEET_OTHER;
2704                         event.p = p;
2705
2706                         // Copy modified_blocks to event
2707                         for(core::map<v3s16, MapBlock*>::Iterator
2708                                         i = modified_blocks.getIterator();
2709                                         i.atEnd()==false; i++)
2710                         {
2711                                 event.modified_blocks.insert(i.getNode()->getKey(), false);
2712                         }
2713
2714                         // Queue event
2715                         dispatchEvent(&event);
2716
2717                         return block;
2718                 }
2719         }*/
2720
2721         return NULL;
2722 }
2723
2724 s16 ServerMap::findGroundLevel(v2s16 p2d)
2725 {
2726 #if 0
2727         /*
2728                 Uh, just do something random...
2729         */
2730         // Find existing map from top to down
2731         s16 max=63;
2732         s16 min=-64;
2733         v3s16 p(p2d.X, max, p2d.Y);
2734         for(; p.Y>min; p.Y--)
2735         {
2736                 MapNode n = getNodeNoEx(p);
2737                 if(n.getContent() != CONTENT_IGNORE)
2738                         break;
2739         }
2740         if(p.Y == min)
2741                 goto plan_b;
2742         // If this node is not air, go to plan b
2743         if(getNodeNoEx(p).getContent() != CONTENT_AIR)
2744                 goto plan_b;
2745         // Search existing walkable and return it
2746         for(; p.Y>min; p.Y--)
2747         {
2748                 MapNode n = getNodeNoEx(p);
2749                 if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
2750                         return p.Y;
2751         }
2752
2753         // Move to plan b
2754 plan_b:
2755 #endif
2756
2757         /*
2758                 Determine from map generator noise functions
2759         */
2760
2761         s16 level = m_emerge->getGroundLevelAtPoint(p2d);
2762         return level;
2763
2764         //double level = base_rock_level_2d(m_seed, p2d) + AVERAGE_MUD_AMOUNT;
2765         //return (s16)level;
2766 }
2767
2768 void ServerMap::createDatabase() {
2769         int e;
2770         assert(m_database);
2771         e = sqlite3_exec(m_database,
2772                 "CREATE TABLE IF NOT EXISTS `blocks` ("
2773                         "`pos` INT NOT NULL PRIMARY KEY,"
2774                         "`data` BLOB"
2775                 ");"
2776         , NULL, NULL, NULL);
2777         if(e == SQLITE_ABORT)
2778                 throw FileNotGoodException("Could not create database structure");
2779         else
2780                 infostream<<"ServerMap: Database structure was created";
2781 }
2782
2783 void ServerMap::verifyDatabase() {
2784         if(m_database)
2785                 return;
2786
2787         {
2788                 std::string dbp = m_savedir + DIR_DELIM + "map.sqlite";
2789                 bool needs_create = false;
2790                 int d;
2791
2792                 /*
2793                         Open the database connection
2794                 */
2795
2796                 createDirs(m_savedir);
2797
2798                 if(!fs::PathExists(dbp))
2799                         needs_create = true;
2800
2801                 d = sqlite3_open_v2(dbp.c_str(), &m_database, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
2802                 if(d != SQLITE_OK) {
2803                         infostream<<"WARNING: Database failed to open: "<<sqlite3_errmsg(m_database)<<std::endl;
2804                         throw FileNotGoodException("Cannot open database file");
2805                 }
2806
2807                 if(needs_create)
2808                         createDatabase();
2809
2810                 d = sqlite3_prepare(m_database, "SELECT `data` FROM `blocks` WHERE `pos`=? LIMIT 1", -1, &m_database_read, NULL);
2811                 if(d != SQLITE_OK) {
2812                         infostream<<"WARNING: Database read statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2813                         throw FileNotGoodException("Cannot prepare read statement");
2814                 }
2815
2816                 d = sqlite3_prepare(m_database, "REPLACE INTO `blocks` VALUES(?, ?)", -1, &m_database_write, NULL);
2817                 if(d != SQLITE_OK) {
2818                         infostream<<"WARNING: Database write statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2819                         throw FileNotGoodException("Cannot prepare write statement");
2820                 }
2821
2822                 d = sqlite3_prepare(m_database, "SELECT `pos` FROM `blocks`", -1, &m_database_list, NULL);
2823                 if(d != SQLITE_OK) {
2824                         infostream<<"WARNING: Database list statment failed to prepare: "<<sqlite3_errmsg(m_database)<<std::endl;
2825                         throw FileNotGoodException("Cannot prepare read statement");
2826                 }
2827
2828                 infostream<<"ServerMap: Database opened"<<std::endl;
2829         }
2830 }
2831
2832 bool ServerMap::loadFromFolders() {
2833         if(!m_database && !fs::PathExists(m_savedir + DIR_DELIM + "map.sqlite"))
2834                 return true;
2835         return false;
2836 }
2837
2838 sqlite3_int64 ServerMap::getBlockAsInteger(const v3s16 pos) {
2839         return (sqlite3_int64)pos.Z*16777216 +
2840                 (sqlite3_int64)pos.Y*4096 + (sqlite3_int64)pos.X;
2841 }
2842
2843 void ServerMap::createDirs(std::string path)
2844 {
2845         if(fs::CreateAllDirs(path) == false)
2846         {
2847                 m_dout<<DTIME<<"ServerMap: Failed to create directory "
2848                                 <<"\""<<path<<"\""<<std::endl;
2849                 throw BaseException("ServerMap failed to create directory");
2850         }
2851 }
2852
2853 std::string ServerMap::getSectorDir(v2s16 pos, int layout)
2854 {
2855         char cc[9];
2856         switch(layout)
2857         {
2858                 case 1:
2859                         snprintf(cc, 9, "%.4x%.4x",
2860                                 (unsigned int)pos.X&0xffff,
2861                                 (unsigned int)pos.Y&0xffff);
2862
2863                         return m_savedir + DIR_DELIM + "sectors" + DIR_DELIM + cc;
2864                 case 2:
2865                         snprintf(cc, 9, "%.3x" DIR_DELIM "%.3x",
2866                                 (unsigned int)pos.X&0xfff,
2867                                 (unsigned int)pos.Y&0xfff);
2868
2869                         return m_savedir + DIR_DELIM + "sectors2" + DIR_DELIM + cc;
2870                 default:
2871                         assert(false);
2872         }
2873 }
2874
2875 v2s16 ServerMap::getSectorPos(std::string dirname)
2876 {
2877         unsigned int x, y;
2878         int r;
2879         size_t spos = dirname.rfind(DIR_DELIM_C) + 1;
2880         assert(spos != std::string::npos);
2881         if(dirname.size() - spos == 8)
2882         {
2883                 // Old layout
2884                 r = sscanf(dirname.substr(spos).c_str(), "%4x%4x", &x, &y);
2885         }
2886         else if(dirname.size() - spos == 3)
2887         {
2888                 // New layout
2889                 r = sscanf(dirname.substr(spos-4).c_str(), "%3x" DIR_DELIM "%3x", &x, &y);
2890                 // Sign-extend the 12 bit values up to 16 bits...
2891                 if(x&0x800) x|=0xF000;
2892                 if(y&0x800) y|=0xF000;
2893         }
2894         else
2895         {
2896                 assert(false);
2897         }
2898         assert(r == 2);
2899         v2s16 pos((s16)x, (s16)y);
2900         return pos;
2901 }
2902
2903 v3s16 ServerMap::getBlockPos(std::string sectordir, std::string blockfile)
2904 {
2905         v2s16 p2d = getSectorPos(sectordir);
2906
2907         if(blockfile.size() != 4){
2908                 throw InvalidFilenameException("Invalid block filename");
2909         }
2910         unsigned int y;
2911         int r = sscanf(blockfile.c_str(), "%4x", &y);
2912         if(r != 1)
2913                 throw InvalidFilenameException("Invalid block filename");
2914         return v3s16(p2d.X, y, p2d.Y);
2915 }
2916
2917 std::string ServerMap::getBlockFilename(v3s16 p)
2918 {
2919         char cc[5];
2920         snprintf(cc, 5, "%.4x", (unsigned int)p.Y&0xffff);
2921         return cc;
2922 }
2923
2924 void ServerMap::save(ModifiedState save_level)
2925 {
2926         DSTACK(__FUNCTION_NAME);
2927         if(m_map_saving_enabled == false)
2928         {
2929                 infostream<<"WARNING: Not saving map, saving disabled."<<std::endl;
2930                 return;
2931         }
2932
2933         if(save_level == MOD_STATE_CLEAN)
2934                 infostream<<"ServerMap: Saving whole map, this can take time."
2935                                 <<std::endl;
2936
2937         if(m_map_metadata_changed || save_level == MOD_STATE_CLEAN)
2938         {
2939                 saveMapMeta();
2940         }
2941
2942         // Profile modified reasons
2943         Profiler modprofiler;
2944
2945         u32 sector_meta_count = 0;
2946         u32 block_count = 0;
2947         u32 block_count_all = 0; // Number of blocks in memory
2948
2949         // Don't do anything with sqlite unless something is really saved
2950         bool save_started = false;
2951
2952         core::map<v2s16, MapSector*>::Iterator i = m_sectors.getIterator();
2953         for(; i.atEnd() == false; i++)
2954         {
2955                 ServerMapSector *sector = (ServerMapSector*)i.getNode()->getValue();
2956                 assert(sector->getId() == MAPSECTOR_SERVER);
2957
2958                 if(sector->differs_from_disk || save_level == MOD_STATE_CLEAN)
2959                 {
2960                         saveSectorMeta(sector);
2961                         sector_meta_count++;
2962                 }
2963                 core::list<MapBlock*> blocks;
2964                 sector->getBlocks(blocks);
2965                 core::list<MapBlock*>::Iterator j;
2966
2967                 for(j=blocks.begin(); j!=blocks.end(); j++)
2968                 {
2969                         MapBlock *block = *j;
2970
2971                         block_count_all++;
2972
2973                         if(block->getModified() >= save_level)
2974                         {
2975                                 // Lazy beginSave()
2976                                 if(!save_started){
2977                                         beginSave();
2978                                         save_started = true;
2979                                 }
2980
2981                                 modprofiler.add(block->getModifiedReason(), 1);
2982
2983                                 saveBlock(block);
2984                                 block_count++;
2985
2986                                 /*infostream<<"ServerMap: Written block ("
2987                                                 <<block->getPos().X<<","
2988                                                 <<block->getPos().Y<<","
2989                                                 <<block->getPos().Z<<")"
2990                                                 <<std::endl;*/
2991                         }
2992                 }
2993         }
2994         if(save_started)
2995                 endSave();
2996
2997         /*
2998                 Only print if something happened or saved whole map
2999         */
3000         if(save_level == MOD_STATE_CLEAN || sector_meta_count != 0
3001                         || block_count != 0)
3002         {
3003                 infostream<<"ServerMap: Written: "
3004                                 <<sector_meta_count<<" sector metadata files, "
3005                                 <<block_count<<" block files"
3006                                 <<", "<<block_count_all<<" blocks in memory."
3007                                 <<std::endl;
3008                 PrintInfo(infostream); // ServerMap/ClientMap:
3009                 infostream<<"Blocks modified by: "<<std::endl;
3010                 modprofiler.print(infostream);
3011         }
3012 }
3013
3014 static s32 unsignedToSigned(s32 i, s32 max_positive)
3015 {
3016         if(i < max_positive)
3017                 return i;
3018         else
3019                 return i - 2*max_positive;
3020 }
3021
3022 // modulo of a negative number does not work consistently in C
3023 static sqlite3_int64 pythonmodulo(sqlite3_int64 i, sqlite3_int64 mod)
3024 {
3025         if(i >= 0)
3026                 return i % mod;
3027         return mod - ((-i) % mod);
3028 }
3029
3030 v3s16 ServerMap::getIntegerAsBlock(sqlite3_int64 i)
3031 {
3032         s32 x = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3033         i = (i - x) / 4096;
3034         s32 y = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3035         i = (i - y) / 4096;
3036         s32 z = unsignedToSigned(pythonmodulo(i, 4096), 2048);
3037         return v3s16(x,y,z);
3038 }
3039
3040 void ServerMap::listAllLoadableBlocks(core::list<v3s16> &dst)
3041 {
3042         if(loadFromFolders()){
3043                 errorstream<<"Map::listAllLoadableBlocks(): Result will be missing "
3044                                 <<"all blocks that are stored in flat files"<<std::endl;
3045         }
3046
3047         {
3048                 verifyDatabase();
3049
3050                 while(sqlite3_step(m_database_list) == SQLITE_ROW)
3051                 {
3052                         sqlite3_int64 block_i = sqlite3_column_int64(m_database_list, 0);
3053                         v3s16 p = getIntegerAsBlock(block_i);
3054                         //dstream<<"block_i="<<block_i<<" p="<<PP(p)<<std::endl;
3055                         dst.push_back(p);
3056                 }
3057         }
3058 }
3059
3060 void ServerMap::saveMapMeta()
3061 {
3062         DSTACK(__FUNCTION_NAME);
3063
3064         /*infostream<<"ServerMap::saveMapMeta(): "
3065                         <<"seed="<<m_seed
3066                         <<std::endl;*/
3067
3068         createDirs(m_savedir);
3069
3070         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3071         std::ofstream os(fullpath.c_str(), std::ios_base::binary);
3072         if(os.good() == false)
3073         {
3074                 infostream<<"ERROR: ServerMap::saveMapMeta(): "
3075                                 <<"could not open"<<fullpath<<std::endl;
3076                 throw FileNotGoodException("Cannot open chunk metadata");
3077         }
3078
3079         Settings params;
3080
3081         m_emerge->setParamsToSettings(&params);
3082         params.writeLines(os);
3083
3084         os<<"[end_of_params]\n";
3085
3086         m_map_metadata_changed = false;
3087 }
3088
3089 void ServerMap::loadMapMeta()
3090 {
3091         DSTACK(__FUNCTION_NAME);
3092
3093         /*infostream<<"ServerMap::loadMapMeta(): Loading map metadata"
3094                         <<std::endl;*/
3095
3096         std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
3097         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3098         if(is.good() == false)
3099         {
3100                 infostream<<"ERROR: ServerMap::loadMapMeta(): "
3101                                 <<"could not open"<<fullpath<<std::endl;
3102                 throw FileNotGoodException("Cannot open map metadata");
3103         }
3104
3105         Settings params;
3106
3107         for(;;)
3108         {
3109                 if(is.eof())
3110                         throw SerializationError
3111                                         ("ServerMap::loadMapMeta(): [end_of_params] not found");
3112                 std::string line;
3113                 std::getline(is, line);
3114                 std::string trimmedline = trim(line);
3115                 if(trimmedline == "[end_of_params]")
3116                         break;
3117                 params.parseConfigLine(line);
3118         }
3119
3120         MapgenParams *mgparams = m_emerge->getParamsFromSettings(&params);
3121         if (mgparams) {
3122                 if (m_mgparams)
3123                         delete m_mgparams;
3124                 m_mgparams = mgparams;
3125                 m_seed = mgparams->seed;
3126         } else {
3127                 if (params.exists("seed")) {
3128                         m_seed = params.getU64("seed");
3129                         m_mgparams->seed = m_seed;
3130                 }
3131         }
3132
3133         verbosestream<<"ServerMap::loadMapMeta(): "<<"seed="<<m_seed<<std::endl;
3134 }
3135
3136 void ServerMap::saveSectorMeta(ServerMapSector *sector)
3137 {
3138         DSTACK(__FUNCTION_NAME);
3139         // Format used for writing
3140         u8 version = SER_FMT_VER_HIGHEST;
3141         // Get destination
3142         v2s16 pos = sector->getPos();
3143         std::string dir = getSectorDir(pos);
3144         createDirs(dir);
3145
3146         std::string fullpath = dir + DIR_DELIM + "meta";
3147         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3148         if(o.good() == false)
3149                 throw FileNotGoodException("Cannot open sector metafile");
3150
3151         sector->serialize(o, version);
3152
3153         sector->differs_from_disk = false;
3154 }
3155
3156 MapSector* ServerMap::loadSectorMeta(std::string sectordir, bool save_after_load)
3157 {
3158         DSTACK(__FUNCTION_NAME);
3159         // Get destination
3160         v2s16 p2d = getSectorPos(sectordir);
3161
3162         ServerMapSector *sector = NULL;
3163
3164         std::string fullpath = sectordir + DIR_DELIM + "meta";
3165         std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3166         if(is.good() == false)
3167         {
3168                 // If the directory exists anyway, it probably is in some old
3169                 // format. Just go ahead and create the sector.
3170                 if(fs::PathExists(sectordir))
3171                 {
3172                         /*infostream<<"ServerMap::loadSectorMeta(): Sector metafile "
3173                                         <<fullpath<<" doesn't exist but directory does."
3174                                         <<" Continuing with a sector with no metadata."
3175                                         <<std::endl;*/
3176                         sector = new ServerMapSector(this, p2d, m_gamedef);
3177                         m_sectors.insert(p2d, sector);
3178                 }
3179                 else
3180                 {
3181                         throw FileNotGoodException("Cannot open sector metafile");
3182                 }
3183         }
3184         else
3185         {
3186                 sector = ServerMapSector::deSerialize
3187                                 (is, this, p2d, m_sectors, m_gamedef);
3188                 if(save_after_load)
3189                         saveSectorMeta(sector);
3190         }
3191
3192         sector->differs_from_disk = false;
3193
3194         return sector;
3195 }
3196
3197 bool ServerMap::loadSectorMeta(v2s16 p2d)
3198 {
3199         DSTACK(__FUNCTION_NAME);
3200
3201         MapSector *sector = NULL;
3202
3203         // The directory layout we're going to load from.
3204         //  1 - original sectors/xxxxzzzz/
3205         //  2 - new sectors2/xxx/zzz/
3206         //  If we load from anything but the latest structure, we will
3207         //  immediately save to the new one, and remove the old.
3208         int loadlayout = 1;
3209         std::string sectordir1 = getSectorDir(p2d, 1);
3210         std::string sectordir;
3211         if(fs::PathExists(sectordir1))
3212         {
3213                 sectordir = sectordir1;
3214         }
3215         else
3216         {
3217                 loadlayout = 2;
3218                 sectordir = getSectorDir(p2d, 2);
3219         }
3220
3221         try{
3222                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3223         }
3224         catch(InvalidFilenameException &e)
3225         {
3226                 return false;
3227         }
3228         catch(FileNotGoodException &e)
3229         {
3230                 return false;
3231         }
3232         catch(std::exception &e)
3233         {
3234                 return false;
3235         }
3236
3237         return true;
3238 }
3239
3240 #if 0
3241 bool ServerMap::loadSectorFull(v2s16 p2d)
3242 {
3243         DSTACK(__FUNCTION_NAME);
3244
3245         MapSector *sector = NULL;
3246
3247         // The directory layout we're going to load from.
3248         //  1 - original sectors/xxxxzzzz/
3249         //  2 - new sectors2/xxx/zzz/
3250         //  If we load from anything but the latest structure, we will
3251         //  immediately save to the new one, and remove the old.
3252         int loadlayout = 1;
3253         std::string sectordir1 = getSectorDir(p2d, 1);
3254         std::string sectordir;
3255         if(fs::PathExists(sectordir1))
3256         {
3257                 sectordir = sectordir1;
3258         }
3259         else
3260         {
3261                 loadlayout = 2;
3262                 sectordir = getSectorDir(p2d, 2);
3263         }
3264
3265         try{
3266                 sector = loadSectorMeta(sectordir, loadlayout != 2);
3267         }
3268         catch(InvalidFilenameException &e)
3269         {
3270                 return false;
3271         }
3272         catch(FileNotGoodException &e)
3273         {
3274                 return false;
3275         }
3276         catch(std::exception &e)
3277         {
3278                 return false;
3279         }
3280
3281         /*
3282                 Load blocks
3283         */
3284         std::vector<fs::DirListNode> list2 = fs::GetDirListing
3285                         (sectordir);
3286         std::vector<fs::DirListNode>::iterator i2;
3287         for(i2=list2.begin(); i2!=list2.end(); i2++)
3288         {
3289                 // We want files
3290                 if(i2->dir)
3291                         continue;
3292                 try{
3293                         loadBlock(sectordir, i2->name, sector, loadlayout != 2);
3294                 }
3295                 catch(InvalidFilenameException &e)
3296                 {
3297                         // This catches unknown crap in directory
3298                 }
3299         }
3300
3301         if(loadlayout != 2)
3302         {
3303                 infostream<<"Sector converted to new layout - deleting "<<
3304                         sectordir1<<std::endl;
3305                 fs::RecursiveDelete(sectordir1);
3306         }
3307
3308         return true;
3309 }
3310 #endif
3311
3312 void ServerMap::beginSave() {
3313         verifyDatabase();
3314         if(sqlite3_exec(m_database, "BEGIN;", NULL, NULL, NULL) != SQLITE_OK)
3315                 infostream<<"WARNING: beginSave() failed, saving might be slow.";
3316 }
3317
3318 void ServerMap::endSave() {
3319         verifyDatabase();
3320         if(sqlite3_exec(m_database, "COMMIT;", NULL, NULL, NULL) != SQLITE_OK)
3321                 infostream<<"WARNING: endSave() failed, map might not have saved.";
3322 }
3323
3324 void ServerMap::saveBlock(MapBlock *block)
3325 {
3326         DSTACK(__FUNCTION_NAME);
3327         /*
3328                 Dummy blocks are not written
3329         */
3330         if(block->isDummy())
3331         {
3332                 /*v3s16 p = block->getPos();
3333                 infostream<<"ServerMap::saveBlock(): WARNING: Not writing dummy block "
3334                                 <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"<<std::endl;*/
3335                 return;
3336         }
3337
3338         // Format used for writing
3339         u8 version = SER_FMT_VER_HIGHEST;
3340         // Get destination
3341         v3s16 p3d = block->getPos();
3342
3343
3344 #if 0
3345         v2s16 p2d(p3d.X, p3d.Z);
3346         std::string sectordir = getSectorDir(p2d);
3347
3348         createDirs(sectordir);
3349
3350         std::string fullpath = sectordir+DIR_DELIM+getBlockFilename(p3d);
3351         std::ofstream o(fullpath.c_str(), std::ios_base::binary);
3352         if(o.good() == false)
3353                 throw FileNotGoodException("Cannot open block data");
3354 #endif
3355         /*
3356                 [0] u8 serialization version
3357                 [1] data
3358         */
3359
3360         verifyDatabase();
3361
3362         std::ostringstream o(std::ios_base::binary);
3363
3364         o.write((char*)&version, 1);
3365
3366         // Write basic data
3367         block->serialize(o, version, true);
3368
3369         // Write block to database
3370
3371         std::string tmp = o.str();
3372         const char *bytes = tmp.c_str();
3373
3374         bool success = true;
3375         if(sqlite3_bind_int64(m_database_write, 1, getBlockAsInteger(p3d)) != SQLITE_OK) {
3376                 infostream<<"WARNING: Block position failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3377                 success = false;
3378         }
3379         if(sqlite3_bind_blob(m_database_write, 2, (void *)bytes, o.tellp(), NULL) != SQLITE_OK) { // TODO this mught not be the right length
3380                 infostream<<"WARNING: Block data failed to bind: "<<sqlite3_errmsg(m_database)<<std::endl;
3381                 success = false;
3382         }
3383         int written = sqlite3_step(m_database_write);
3384         if(written != SQLITE_DONE) {
3385                 errorstream<<"WARNING: Block failed to save ("<<p3d.X<<", "<<p3d.Y<<", "<<p3d.Z<<") "
3386                                 <<sqlite3_errmsg(m_database)<<std::endl;
3387                 success = false;
3388         }
3389         // Make ready for later reuse
3390         sqlite3_reset(m_database_write);
3391
3392         // We just wrote it to the disk so clear modified flag
3393         if (success)
3394                 block->resetModified();
3395 }
3396
3397 void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSector *sector, bool save_after_load)
3398 {
3399         DSTACK(__FUNCTION_NAME);
3400
3401         std::string fullpath = sectordir+DIR_DELIM+blockfile;
3402         try{
3403
3404                 std::ifstream is(fullpath.c_str(), std::ios_base::binary);
3405                 if(is.good() == false)
3406                         throw FileNotGoodException("Cannot open block file");
3407
3408                 v3s16 p3d = getBlockPos(sectordir, blockfile);
3409                 v2s16 p2d(p3d.X, p3d.Z);
3410
3411                 assert(sector->getPos() == p2d);
3412
3413                 u8 version = SER_FMT_VER_INVALID;
3414                 is.read((char*)&version, 1);
3415
3416                 if(is.fail())
3417                         throw SerializationError("ServerMap::loadBlock(): Failed"
3418                                         " to read MapBlock version");
3419
3420                 /*u32 block_size = MapBlock::serializedLength(version);
3421                 SharedBuffer<u8> data(block_size);
3422                 is.read((char*)*data, block_size);*/
3423
3424                 // This will always return a sector because we're the server
3425                 //MapSector *sector = emergeSector(p2d);
3426
3427                 MapBlock *block = NULL;
3428                 bool created_new = false;
3429                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3430                 if(block == NULL)
3431                 {
3432                         block = sector->createBlankBlockNoInsert(p3d.Y);
3433                         created_new = true;
3434                 }
3435
3436                 // Read basic data
3437                 block->deSerialize(is, version, true);
3438
3439                 // If it's a new block, insert it to the map
3440                 if(created_new)
3441                         sector->insertBlock(block);
3442
3443                 /*
3444                         Save blocks loaded in old format in new format
3445                 */
3446
3447                 if(version < SER_FMT_VER_HIGHEST || save_after_load)
3448                 {
3449                         saveBlock(block);
3450
3451                         // Should be in database now, so delete the old file
3452                         fs::RecursiveDelete(fullpath);
3453                 }
3454
3455                 // We just loaded it from the disk, so it's up-to-date.
3456                 block->resetModified();
3457
3458         }
3459         catch(SerializationError &e)
3460         {
3461                 infostream<<"WARNING: Invalid block data on disk "
3462                                 <<"fullpath="<<fullpath
3463                                 <<" (SerializationError). "
3464                                 <<"what()="<<e.what()
3465                                 <<std::endl;
3466                                 //" Ignoring. A new one will be generated.
3467                 assert(0);
3468
3469                 // TODO: Backup file; name is in fullpath.
3470         }
3471 }
3472
3473 void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load)
3474 {
3475         DSTACK(__FUNCTION_NAME);
3476
3477         try {
3478                 std::istringstream is(*blob, std::ios_base::binary);
3479
3480                 u8 version = SER_FMT_VER_INVALID;
3481                 is.read((char*)&version, 1);
3482
3483                 if(is.fail())
3484                         throw SerializationError("ServerMap::loadBlock(): Failed"
3485                                         " to read MapBlock version");
3486
3487                 /*u32 block_size = MapBlock::serializedLength(version);
3488                 SharedBuffer<u8> data(block_size);
3489                 is.read((char*)*data, block_size);*/
3490
3491                 // This will always return a sector because we're the server
3492                 //MapSector *sector = emergeSector(p2d);
3493
3494                 MapBlock *block = NULL;
3495                 bool created_new = false;
3496                 block = sector->getBlockNoCreateNoEx(p3d.Y);
3497                 if(block == NULL)
3498                 {
3499                         block = sector->createBlankBlockNoInsert(p3d.Y);
3500                         created_new = true;
3501                 }
3502
3503                 // Read basic data
3504                 block->deSerialize(is, version, true);
3505
3506                 // If it's a new block, insert it to the map
3507                 if(created_new)
3508                         sector->insertBlock(block);
3509
3510                 /*
3511                         Save blocks loaded in old format in new format
3512                 */
3513
3514                 //if(version < SER_FMT_VER_HIGHEST || save_after_load)
3515                 // Only save if asked to; no need to update version
3516                 if(save_after_load)
3517                         saveBlock(block);
3518
3519                 // We just loaded it from, so it's up-to-date.
3520                 block->resetModified();
3521
3522         }
3523         catch(SerializationError &e)
3524         {
3525                 errorstream<<"Invalid block data in database"
3526                                 <<" ("<<p3d.X<<","<<p3d.Y<<","<<p3d.Z<<")"
3527                                 <<" (SerializationError): "<<e.what()<<std::endl;
3528
3529                 // TODO: Block should be marked as invalid in memory so that it is
3530                 // not touched but the game can run
3531
3532                 if(g_settings->getBool("ignore_world_load_errors")){
3533                         errorstream<<"Ignoring block load error. Duck and cover! "
3534                                         <<"(ignore_world_load_errors)"<<std::endl;
3535                 } else {
3536                         throw SerializationError("Invalid block data in database");
3537                         //assert(0);
3538                 }
3539         }
3540 }
3541
3542 MapBlock* ServerMap::loadBlock(v3s16 blockpos)
3543 {
3544         DSTACK(__FUNCTION_NAME);
3545
3546         v2s16 p2d(blockpos.X, blockpos.Z);
3547
3548         if(!loadFromFolders()) {
3549                 verifyDatabase();
3550
3551                 if(sqlite3_bind_int64(m_database_read, 1, getBlockAsInteger(blockpos)) != SQLITE_OK)
3552                         infostream<<"WARNING: Could not bind block position for load: "
3553                                 <<sqlite3_errmsg(m_database)<<std::endl;
3554                 if(sqlite3_step(m_database_read) == SQLITE_ROW) {
3555                         /*
3556                                 Make sure sector is loaded
3557                         */
3558                         MapSector *sector = createSector(p2d);
3559
3560                         /*
3561                                 Load block
3562                         */
3563                         const char * data = (const char *)sqlite3_column_blob(m_database_read, 0);
3564                         size_t len = sqlite3_column_bytes(m_database_read, 0);
3565
3566                         std::string datastr(data, len);
3567
3568                         loadBlock(&datastr, blockpos, sector, false);
3569
3570                         sqlite3_step(m_database_read);
3571                         // We should never get more than 1 row, so ok to reset
3572                         sqlite3_reset(m_database_read);
3573
3574                         return getBlockNoCreateNoEx(blockpos);
3575                 }
3576                 sqlite3_reset(m_database_read);
3577
3578                 // Not found in database, try the files
3579         }
3580
3581         // The directory layout we're going to load from.
3582         //  1 - original sectors/xxxxzzzz/
3583         //  2 - new sectors2/xxx/zzz/
3584         //  If we load from anything but the latest structure, we will
3585         //  immediately save to the new one, and remove the old.
3586         int loadlayout = 1;
3587         std::string sectordir1 = getSectorDir(p2d, 1);
3588         std::string sectordir;
3589         if(fs::PathExists(sectordir1))
3590         {
3591                 sectordir = sectordir1;
3592         }
3593         else
3594         {
3595                 loadlayout = 2;
3596                 sectordir = getSectorDir(p2d, 2);
3597         }
3598
3599         /*
3600                 Make sure sector is loaded
3601         */
3602         MapSector *sector = getSectorNoGenerateNoEx(p2d);
3603         if(sector == NULL)
3604         {
3605                 try{
3606                         sector = loadSectorMeta(sectordir, loadlayout != 2);
3607                 }
3608                 catch(InvalidFilenameException &e)
3609                 {
3610                         return NULL;
3611                 }
3612                 catch(FileNotGoodException &e)
3613                 {
3614                         return NULL;
3615                 }
3616                 catch(std::exception &e)
3617                 {
3618                         return NULL;
3619                 }
3620         }
3621
3622         /*
3623                 Make sure file exists
3624         */
3625
3626         std::string blockfilename = getBlockFilename(blockpos);
3627         if(fs::PathExists(sectordir+DIR_DELIM+blockfilename) == false)
3628                 return NULL;
3629
3630         /*
3631                 Load block and save it to the database
3632         */
3633         loadBlock(sectordir, blockfilename, sector, true);
3634         return getBlockNoCreateNoEx(blockpos);
3635 }
3636
3637 void ServerMap::PrintInfo(std::ostream &out)
3638 {
3639         out<<"ServerMap: ";
3640 }
3641
3642 /*
3643         MapVoxelManipulator
3644 */
3645
3646 MapVoxelManipulator::MapVoxelManipulator(Map *map)
3647 {
3648         m_map = map;
3649 }
3650
3651 MapVoxelManipulator::~MapVoxelManipulator()
3652 {
3653         /*infostream<<"MapVoxelManipulator: blocks: "<<m_loaded_blocks.size()
3654                         <<std::endl;*/
3655 }
3656
3657 void MapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3658 {
3659         TimeTaker timer1("emerge", &emerge_time);
3660
3661         // Units of these are MapBlocks
3662         v3s16 p_min = getNodeBlockPos(a.MinEdge);
3663         v3s16 p_max = getNodeBlockPos(a.MaxEdge);
3664
3665         VoxelArea block_area_nodes
3666                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3667
3668         addArea(block_area_nodes);
3669
3670         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3671         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3672         for(s32 x=p_min.X; x<=p_max.X; x++)
3673         {
3674                 v3s16 p(x,y,z);
3675                 core::map<v3s16, bool>::Node *n;
3676                 n = m_loaded_blocks.find(p);
3677                 if(n != NULL)
3678                         continue;
3679
3680                 bool block_data_inexistent = false;
3681                 try
3682                 {
3683                         TimeTaker timer1("emerge load", &emerge_load_time);
3684
3685                         /*infostream<<"Loading block (caller_id="<<caller_id<<")"
3686                                         <<" ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3687                                         <<" wanted area: ";
3688                         a.print(infostream);
3689                         infostream<<std::endl;*/
3690
3691                         MapBlock *block = m_map->getBlockNoCreate(p);
3692                         if(block->isDummy())
3693                                 block_data_inexistent = true;
3694                         else
3695                                 block->copyTo(*this);
3696                 }
3697                 catch(InvalidPositionException &e)
3698                 {
3699                         block_data_inexistent = true;
3700                 }
3701
3702                 if(block_data_inexistent)
3703                 {
3704                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3705                         // Fill with VOXELFLAG_INEXISTENT
3706                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3707                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3708                         {
3709                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3710                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3711                         }
3712                 }
3713
3714                 m_loaded_blocks.insert(p, !block_data_inexistent);
3715         }
3716
3717         //infostream<<"emerge done"<<std::endl;
3718 }
3719
3720 /*
3721         SUGG: Add an option to only update eg. water and air nodes.
3722               This will make it interfere less with important stuff if
3723                   run on background.
3724 */
3725 void MapVoxelManipulator::blitBack
3726                 (core::map<v3s16, MapBlock*> & modified_blocks)
3727 {
3728         if(m_area.getExtent() == v3s16(0,0,0))
3729                 return;
3730
3731         //TimeTaker timer1("blitBack");
3732
3733         /*infostream<<"blitBack(): m_loaded_blocks.size()="
3734                         <<m_loaded_blocks.size()<<std::endl;*/
3735
3736         /*
3737                 Initialize block cache
3738         */
3739         v3s16 blockpos_last;
3740         MapBlock *block = NULL;
3741         bool block_checked_in_modified = false;
3742
3743         for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++)
3744         for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++)
3745         for(s32 x=m_area.MinEdge.X; x<=m_area.MaxEdge.X; x++)
3746         {
3747                 v3s16 p(x,y,z);
3748
3749                 u8 f = m_flags[m_area.index(p)];
3750                 if(f & (VOXELFLAG_NOT_LOADED|VOXELFLAG_INEXISTENT))
3751                         continue;
3752
3753                 MapNode &n = m_data[m_area.index(p)];
3754
3755                 v3s16 blockpos = getNodeBlockPos(p);
3756
3757                 try
3758                 {
3759                         // Get block
3760                         if(block == NULL || blockpos != blockpos_last){
3761                                 block = m_map->getBlockNoCreate(blockpos);
3762                                 blockpos_last = blockpos;
3763                                 block_checked_in_modified = false;
3764                         }
3765
3766                         // Calculate relative position in block
3767                         v3s16 relpos = p - blockpos * MAP_BLOCKSIZE;
3768
3769                         // Don't continue if nothing has changed here
3770                         if(block->getNode(relpos) == n)
3771                                 continue;
3772
3773                         //m_map->setNode(m_area.MinEdge + p, n);
3774                         block->setNode(relpos, n);
3775
3776                         /*
3777                                 Make sure block is in modified_blocks
3778                         */
3779                         if(block_checked_in_modified == false)
3780                         {
3781                                 modified_blocks[blockpos] = block;
3782                                 block_checked_in_modified = true;
3783                         }
3784                 }
3785                 catch(InvalidPositionException &e)
3786                 {
3787                 }
3788         }
3789 }
3790
3791 ManualMapVoxelManipulator::ManualMapVoxelManipulator(Map *map):
3792                 MapVoxelManipulator(map),
3793                 m_create_area(false)
3794 {
3795 }
3796
3797 ManualMapVoxelManipulator::~ManualMapVoxelManipulator()
3798 {
3799 }
3800
3801 void ManualMapVoxelManipulator::emerge(VoxelArea a, s32 caller_id)
3802 {
3803         // Just create the area so that it can be pointed to
3804         VoxelManipulator::emerge(a, caller_id);
3805 }
3806
3807 void ManualMapVoxelManipulator::initialEmerge(
3808                 v3s16 blockpos_min, v3s16 blockpos_max)
3809 {
3810         TimeTaker timer1("initialEmerge", &emerge_time);
3811
3812         // Units of these are MapBlocks
3813         v3s16 p_min = blockpos_min;
3814         v3s16 p_max = blockpos_max;
3815
3816         VoxelArea block_area_nodes
3817                         (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3818
3819         u32 size_MB = block_area_nodes.getVolume()*4/1000000;
3820         if(size_MB >= 1)
3821         {
3822                 infostream<<"initialEmerge: area: ";
3823                 block_area_nodes.print(infostream);
3824                 infostream<<" ("<<size_MB<<"MB)";
3825                 infostream<<std::endl;
3826         }
3827
3828         addArea(block_area_nodes);
3829
3830         for(s32 z=p_min.Z; z<=p_max.Z; z++)
3831         for(s32 y=p_min.Y; y<=p_max.Y; y++)
3832         for(s32 x=p_min.X; x<=p_max.X; x++)
3833         {
3834                 v3s16 p(x,y,z);
3835                 core::map<v3s16, bool>::Node *n;
3836                 n = m_loaded_blocks.find(p);
3837                 if(n != NULL)
3838                         continue;
3839
3840                 bool block_data_inexistent = false;
3841                 try
3842                 {
3843                         TimeTaker timer1("emerge load", &emerge_load_time);
3844
3845                         MapBlock *block = m_map->getBlockNoCreate(p);
3846                         if(block->isDummy())
3847                                 block_data_inexistent = true;
3848                         else
3849                                 block->copyTo(*this);
3850                 }
3851                 catch(InvalidPositionException &e)
3852                 {
3853                         block_data_inexistent = true;
3854                 }
3855
3856                 if(block_data_inexistent)
3857                 {
3858                         /*
3859                                 Mark area inexistent
3860                         */
3861                         VoxelArea a(p*MAP_BLOCKSIZE, (p+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
3862                         // Fill with VOXELFLAG_INEXISTENT
3863                         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
3864                         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
3865                         {
3866                                 s32 i = m_area.index(a.MinEdge.X,y,z);
3867                                 memset(&m_flags[i], VOXELFLAG_INEXISTENT, MAP_BLOCKSIZE);
3868                         }
3869                 }
3870
3871                 m_loaded_blocks.insert(p, !block_data_inexistent);
3872         }
3873 }
3874
3875 void ManualMapVoxelManipulator::blitBackAll(
3876                 core::map<v3s16, MapBlock*> * modified_blocks)
3877 {
3878         if(m_area.getExtent() == v3s16(0,0,0))
3879                 return;
3880
3881         /*
3882                 Copy data of all blocks
3883         */
3884         for(core::map<v3s16, bool>::Iterator
3885                         i = m_loaded_blocks.getIterator();
3886                         i.atEnd() == false; i++)
3887         {
3888                 v3s16 p = i.getNode()->getKey();
3889                 bool existed = i.getNode()->getValue();
3890                 if(existed == false)
3891                 {
3892                         // The Great Bug was found using this
3893                         /*infostream<<"ManualMapVoxelManipulator::blitBackAll: "
3894                                         <<"Inexistent ("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3895                                         <<std::endl;*/
3896                         continue;
3897                 }
3898                 MapBlock *block = m_map->getBlockNoCreateNoEx(p);
3899                 if(block == NULL)
3900                 {
3901                         infostream<<"WARNING: "<<__FUNCTION_NAME
3902                                         <<": got NULL block "
3903                                         <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
3904                                         <<std::endl;
3905                         continue;
3906                 }
3907
3908                 block->copyFrom(*this);
3909
3910                 if(modified_blocks)
3911                         modified_blocks->insert(p, block);
3912         }
3913 }
3914
3915 //END