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