Translated using Weblate (Japanese)
[oweals/minetest.git] / src / map.cpp
index e80c8252276055cc0fa71d168874c476bb05bcbe..76a558d43cebf90f90ae8fd02714ffe61c1d2ac2 100644 (file)
@@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "map.h"
 #include "mapsector.h"
 #include "mapblock.h"
-#include "main.h"
 #include "filesys.h"
 #include "voxel.h"
 #include "porting.h"
@@ -44,6 +43,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "database-dummy.h"
 #include "database-sqlite3.h"
 #include <deque>
+#include <queue>
 #if USE_LEVELDB
 #include "database-leveldb.h"
 #endif
@@ -767,8 +767,7 @@ void Map::updateLighting(enum LightBank bank,
                        }
                        else
                        {
-                               // Invalid lighting bank
-                               assert(0);
+                               assert("Invalid lighting bank" == NULL);
                        }
 
                        /*infostream<<"Bottom for sunlight-propagated block ("
@@ -783,7 +782,7 @@ void Map::updateLighting(enum LightBank bank,
                        }
                        catch(InvalidPositionException &e)
                        {
-                               assert(0);
+                               FATAL_ERROR("Invalid position");
                        }
 
                }
@@ -1220,7 +1219,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
                        n.setLight(LIGHTBANK_DAY, 0, ndef);
                        setNode(p, n);
                } else {
-                       assert(0);
+                       FATAL_ERROR("Invalid position");
                }
        }
 
@@ -1401,10 +1400,25 @@ bool Map::getDayNightDiff(v3s16 blockpos)
        return false;
 }
 
+struct TimeOrderedMapBlock {
+       MapSector *sect;
+       MapBlock *block;
+
+       TimeOrderedMapBlock(MapSector *sect, MapBlock *block) :
+               sect(sect),
+               block(block)
+       {}
+
+       bool operator<(const TimeOrderedMapBlock &b) const
+       {
+               return block->getUsageTimer() < b.block->getUsageTimer();
+       };
+};
+
 /*
        Updates usage timers
 */
-void Map::timerUpdate(float dtime, float unload_timeout,
+void Map::timerUpdate(float dtime, float unload_timeout, u32 max_loaded_blocks,
                std::vector<v3s16> *unloaded_blocks)
 {
        bool save_before_unloading = (mapType() == MAPTYPE_SERVER);
@@ -1418,48 +1432,108 @@ void Map::timerUpdate(float dtime, float unload_timeout,
        u32 block_count_all = 0;
 
        beginSave();
-       for(std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
-               si != m_sectors.end(); ++si) {
-               MapSector *sector = si->second;
 
-               bool all_blocks_deleted = true;
+       // If there is no practical limit, we spare creation of mapblock_queue
+       if (max_loaded_blocks == (u32)-1) {
+               for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+                               si != m_sectors.end(); ++si) {
+                       MapSector *sector = si->second;
 
-               MapBlockVect blocks;
-               sector->getBlocks(blocks);
+                       bool all_blocks_deleted = true;
 
-               for(MapBlockVect::iterator i = blocks.begin();
-                               i != blocks.end(); ++i) {
-                       MapBlock *block = (*i);
+                       MapBlockVect blocks;
+                       sector->getBlocks(blocks);
 
-                       block->incrementUsageTimer(dtime);
+                       for (MapBlockVect::iterator i = blocks.begin();
+                                       i != blocks.end(); ++i) {
+                               MapBlock *block = (*i);
 
-                       if(block->refGet() == 0 && block->getUsageTimer() > unload_timeout) {
-                               v3s16 p = block->getPos();
+                               block->incrementUsageTimer(dtime);
 
-                               // Save if modified
-                               if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
-                                       modprofiler.add(block->getModifiedReason(), 1);
-                                       if (!saveBlock(block))
-                                               continue;
-                                       saved_blocks_count++;
-                               }
+                               if (block->refGet() == 0
+                                               && block->getUsageTimer() > unload_timeout) {
+                                       v3s16 p = block->getPos();
+
+                                       // Save if modified
+                                       if (block->getModified() != MOD_STATE_CLEAN
+                                                       && save_before_unloading) {
+                                               modprofiler.add(block->getModifiedReasonString(), 1);
+                                               if (!saveBlock(block))
+                                                       continue;
+                                               saved_blocks_count++;
+                                       }
 
-                               // Delete from memory
-                               sector->deleteBlock(block);
+                                       // Delete from memory
+                                       sector->deleteBlock(block);
 
-                               if(unloaded_blocks)
-                                       unloaded_blocks->push_back(p);
+                                       if (unloaded_blocks)
+                                               unloaded_blocks->push_back(p);
 
-                               deleted_blocks_count++;
+                                       deleted_blocks_count++;
+                               } else {
+                                       all_blocks_deleted = false;
+                                       block_count_all++;
+                               }
                        }
-                       else {
-                               all_blocks_deleted = false;
-                               block_count_all++;
+
+                       if (all_blocks_deleted) {
+                               sector_deletion_queue.push_back(si->first);
                        }
                }
+       } else {
+               std::priority_queue<TimeOrderedMapBlock> mapblock_queue;
+               for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+                               si != m_sectors.end(); ++si) {
+                       MapSector *sector = si->second;
+
+                       MapBlockVect blocks;
+                       sector->getBlocks(blocks);
+
+                       for(MapBlockVect::iterator i = blocks.begin();
+                                       i != blocks.end(); ++i) {
+                               MapBlock *block = (*i);
+
+                               block->incrementUsageTimer(dtime);
+                               mapblock_queue.push(TimeOrderedMapBlock(sector, block));
+                       }
+               }
+               block_count_all = mapblock_queue.size();
+               // Delete old blocks, and blocks over the limit from the memory
+               while (!mapblock_queue.empty() && (mapblock_queue.size() > max_loaded_blocks
+                               || mapblock_queue.top().block->getUsageTimer() > unload_timeout)) {
+                       TimeOrderedMapBlock b = mapblock_queue.top();
+                       mapblock_queue.pop();
+
+                       MapBlock *block = b.block;
+
+                       if (block->refGet() != 0)
+                               continue;
+
+                       v3s16 p = block->getPos();
+
+                       // Save if modified
+                       if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) {
+                               modprofiler.add(block->getModifiedReasonString(), 1);
+                               if (!saveBlock(block))
+                                       continue;
+                               saved_blocks_count++;
+                       }
+
+                       // Delete from memory
+                       b.sect->deleteBlock(block);
 
-               if(all_blocks_deleted) {
-                       sector_deletion_queue.push_back(si->first);
+                       if (unloaded_blocks)
+                               unloaded_blocks->push_back(p);
+
+                       deleted_blocks_count++;
+                       block_count_all--;
+               }
+               // Delete empty sectors
+               for (std::map<v2s16, MapSector*>::iterator si = m_sectors.begin();
+                       si != m_sectors.end(); ++si) {
+                       if (si->second->empty()) {
+                               sector_deletion_queue.push_back(si->first);
+                       }
                }
        }
        endSave();
@@ -1486,7 +1560,7 @@ void Map::timerUpdate(float dtime, float unload_timeout,
 
 void Map::unloadUnreferencedBlocks(std::vector<v3s16> *unloaded_blocks)
 {
-       timerUpdate(0.0, -1.0, unloaded_blocks);
+       timerUpdate(0.0, -1.0, 0, unloaded_blocks);
 }
 
 void Map::deleteSectors(std::vector<v2s16> &sectorList)
@@ -1892,6 +1966,47 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks)
        }
 }
 
+std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
+{
+       std::vector<v3s16> positions_with_meta;
+
+       sortBoxVerticies(p1, p2);
+       v3s16 bpmin = getNodeBlockPos(p1);
+       v3s16 bpmax = getNodeBlockPos(p2);
+
+       VoxelArea area(p1, p2);
+
+       for (s16 z = bpmin.Z; z <= bpmax.Z; z++)
+       for (s16 y = bpmin.Y; y <= bpmax.Y; y++)
+       for (s16 x = bpmin.X; x <= bpmax.X; x++) {
+               v3s16 blockpos(x, y, z);
+
+               MapBlock *block = getBlockNoCreateNoEx(blockpos);
+               if (!block) {
+                       verbosestream << "Map::getNodeMetadata(): Need to emerge "
+                               << PP(blockpos) << std::endl;
+                       block = emergeBlock(blockpos, false);
+               }
+               if (!block) {
+                       infostream << "WARNING: Map::getNodeMetadata(): Block not found"
+                               << std::endl;
+                       continue;
+               }
+
+               v3s16 p_base = blockpos * MAP_BLOCKSIZE;
+               std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
+               for (size_t i = 0; i != keys.size(); i++) {
+                       v3s16 p(keys[i] + p_base);
+                       if (!area.contains(p))
+                               continue;
+
+                       positions_with_meta.push_back(p);
+               }
+       }
+
+       return positions_with_meta;
+}
+
 NodeMetadata *Map::getNodeMetadata(v3s16 p)
 {
        v3s16 blockpos = getNodeBlockPos(p);
@@ -2180,7 +2295,7 @@ bool ServerMap::initBlockMake(BlockMakeData *data, v3s16 blockpos)
                        v2s16 sectorpos(x, z);
                        // Sector metadata is loaded from disk if not already loaded.
                        ServerMapSector *sector = createSector(sectorpos);
-                       assert(sector);
+                       FATAL_ERROR_IF(sector == NULL, "createSector() failed");
                        (void) sector;
 
                        for(s16 y=blockpos_min.Y-extra_borders.Y;
@@ -2373,7 +2488,7 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
                        Set block as modified
                */
                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                               "finishBlockMake expireDayNightDiff");
+                       MOD_REASON_EXPIRE_DAYNIGHTDIFF);
        }
 
        /*
@@ -2463,10 +2578,12 @@ ServerMapSector * ServerMap::createSector(v2s16 p2d)
        /*
                Do not create over-limit
        */
-       if(p2d.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p2d.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p2d.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p2d.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
+       const static u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT,
+               g_settings->getU16("map_generation_limit"));
+       if(p2d.X < -map_gen_limit / MAP_BLOCKSIZE
+                       || p2d.X >  map_gen_limit / MAP_BLOCKSIZE
+                       || p2d.Y < -map_gen_limit / MAP_BLOCKSIZE
+                       || p2d.Y >  map_gen_limit / MAP_BLOCKSIZE)
                throw InvalidPositionException("createSector(): pos. over limit");
 
        /*
@@ -2610,12 +2727,7 @@ MapBlock * ServerMap::createBlock(v3s16 p)
        /*
                Do not create over-limit
        */
-       if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
-       || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
+       if (blockpos_over_limit(p))
                throw InvalidPositionException("createBlock(): pos. over limit");
 
        v2s16 p2d(p.X, p.Z);
@@ -2628,7 +2740,7 @@ MapBlock * ServerMap::createBlock(v3s16 p)
                      lighting on blocks for them.
        */
        ServerMapSector *sector;
-       try{
+       try {
                sector = (ServerMapSector*)createSector(p2d);
                assert(sector->getId() == MAPSECTOR_SERVER);
        }
@@ -2861,9 +2973,10 @@ v2s16 ServerMap::getSectorPos(std::string dirname)
        }
        else
        {
-               assert(false);
+               r = -1;
        }
-       assert(r == 2);
+
+       FATAL_ERROR_IF(r != 2, "getSectorPos()");
        v2s16 pos((s16)x, (s16)y);
        return pos;
 }
@@ -2941,7 +3054,7 @@ void ServerMap::save(ModifiedState save_level)
                                        save_started = true;
                                }
 
-                               modprofiler.add(block->getModifiedReason(), 1);
+                               modprofiler.add(block->getModifiedReasonString(), 1);
 
                                saveBlock(block);
                                block_count++;
@@ -3005,26 +3118,20 @@ void ServerMap::saveMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
 
-       /*infostream<<"ServerMap::saveMapMeta(): "
-                       <<"seed="<<m_seed
-                       <<std::endl;*/
-
        createDirs(m_savedir);
 
-       std::string fullpath = m_savedir + DIR_DELIM "map_meta.txt";
-       std::ostringstream ss(std::ios_base::binary);
-
-       Settings params;
+       std::string fullpath = m_savedir + DIR_DELIM + "map_meta.txt";
+       std::ostringstream oss(std::ios_base::binary);
+       Settings conf;
 
-       m_emerge->saveParamsToSettings(&params);
-       params.writeLines(ss);
+       m_emerge->params.save(conf);
+       conf.writeLines(oss);
 
-       ss<<"[end_of_params]\n";
+       oss << "[end_of_params]\n";
 
-       if(!fs::safeWriteToFile(fullpath, ss.str()))
-       {
-               infostream<<"ERROR: ServerMap::saveMapMeta(): "
-                               <<"could not write "<<fullpath<<std::endl;
+       if(!fs::safeWriteToFile(fullpath, oss.str())) {
+               errorstream << "ServerMap::saveMapMeta(): "
+                               << "could not write " << fullpath << std::endl;
                throw FileNotGoodException("Cannot save chunk metadata");
        }
 
@@ -3035,24 +3142,22 @@ void ServerMap::loadMapMeta()
 {
        DSTACK(__FUNCTION_NAME);
 
-       Settings params;
-       std::string fullpath = m_savedir + DIR_DELIM "map_meta.txt";
+       Settings conf;
+       std::string fullpath = m_savedir + DIR_DELIM "map_meta.txt";
 
-       if (fs::PathExists(fullpath)) {
-               std::ifstream is(fullpath.c_str(), std::ios_base::binary);
-               if (!is.good()) {
-                       errorstream << "ServerMap::loadMapMeta(): "
-                               "could not open " << fullpath << std::endl;
-                       throw FileNotGoodException("Cannot open map metadata");
-               }
+       std::ifstream is(fullpath.c_str(), std::ios_base::binary);
+       if (!is.good()) {
+               errorstream << "ServerMap::loadMapMeta(): "
+                       "could not open " << fullpath << std::endl;
+               throw FileNotGoodException("Cannot open map metadata");
+       }
 
-               if (!params.parseConfigLines(is, "[end_of_params]")) {
-                       throw SerializationError("ServerMap::loadMapMeta(): "
+       if (!conf.parseConfigLines(is, "[end_of_params]")) {
+               throw SerializationError("ServerMap::loadMapMeta(): "
                                "[end_of_params] not found!");
-               }
        }
 
-       m_emerge->loadParamsFromSettings(&params);
+       m_emerge->params.load(conf);
 
        verbosestream << "ServerMap::loadMapMeta(): seed="
                << m_emerge->params.seed << std::endl;
@@ -3368,7 +3473,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile,
                                <<"what()="<<e.what()
                                <<std::endl;
                                // Ignoring. A new one will be generated.
-               assert(0);
+               abort();
 
                // TODO: Backup file; name is in fullpath.
        }
@@ -3438,7 +3543,6 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool
                                        <<"(ignore_world_load_errors)"<<std::endl;
                } else {
                        throw SerializationError("Invalid block data in database");
-                       //assert(0);
                }
        }
 }