Translated using Weblate (Japanese)
[oweals/minetest.git] / src / map.cpp
index 7f8059cc480e6f7825f9b25a8d1e9da7a1994418..76a558d43cebf90f90ae8fd02714ffe61c1d2ac2 100644 (file)
@@ -43,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
@@ -1399,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);
@@ -1416,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);
 
-               if(all_blocks_deleted) {
-                       sector_deletion_queue.push_back(si->first);
+                               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 (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();
@@ -1484,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)
@@ -1898,6 +1974,8 @@ std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 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++) {
@@ -1917,8 +1995,13 @@ std::vector<v3s16> Map::findNodesWithMetadata(v3s16 p1, v3s16 p2)
 
                v3s16 p_base = blockpos * MAP_BLOCKSIZE;
                std::vector<v3s16> keys = block->m_node_metadata.getAllKeys();
-               for (size_t i = 0; i != keys.size(); i++)
-                       positions_with_meta.push_back(keys[i] + p_base);
+               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;
@@ -2405,7 +2488,7 @@ void ServerMap::finishBlockMake(BlockMakeData *data,
                        Set block as modified
                */
                block->raiseModified(MOD_STATE_WRITE_NEEDED,
-                               "finishBlockMake expireDayNightDiff");
+                       MOD_REASON_EXPIRE_DAYNIGHTDIFF);
        }
 
        /*
@@ -2495,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");
 
        /*
@@ -2642,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);
@@ -2974,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++;