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