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