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