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