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