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