From: Perttu Ahola Date: Sun, 26 Jun 2011 21:27:17 +0000 (+0300) Subject: map unloading is now a whole lot better X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=dd22ea051a643a1ca2657958c8552849dc1ffa36;p=zefram%2Fminetest%2Fminetest_engine.git map unloading is now a whole lot better --- diff --git a/minetest.conf.example b/minetest.conf.example index 6e8a82ba..f94c8dee 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -9,6 +9,10 @@ # # Further documentation: # http://celeron.55.lt/~celeron55/minetest/wiki/doku.php +# +# NOTE: This file might not be up-to-date, refer to the +# defaultsettings.cpp file for an up-to-date list: +# https://bitbucket.org/celeron55/minetest/src/tip/src/defaultsettings.cpp # # Client side stuff @@ -92,7 +96,7 @@ #random_input = false # Timeout for client to remove unused map data from memory -#client_delete_unused_sectors_timeout = 1200 +#client_unload_unused_data_timeout = 1200 # # Server side stuff @@ -140,6 +144,6 @@ #time_speed = 1440 #time_send_interval = 5 -#server_unload_unused_sectors_timeout = 60 +#server_unload_unused_data_timeout = 60 #server_map_save_interval = 60 diff --git a/src/client.cpp b/src/client.cpp index 449b0c2f..585fce11 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -199,7 +199,7 @@ Client::Client( m_access_denied(false) { m_packetcounter_timer = 0.0; - m_delete_unused_sectors_timer = 0.0; + //m_delete_unused_sectors_timer = 0.0; m_connection_reinit_timer = 0.0; m_avg_rtt_timer = 0.0; m_playerpos_send_timer = 0.0; @@ -303,7 +303,11 @@ void Client::step(float dtime) m_packetcounter.clear(); } } + + // Get connection status + bool connected = connectedAndInitialized(); +#if 0 { /* Delete unused sectors @@ -324,8 +328,7 @@ void Client::step(float dtime) core::list deleted_blocks; - float delete_unused_sectors_timeout = - g_settings.getFloat("client_delete_unused_sectors_timeout"); + g_settings.getFloat("client_unload_unused_data_timeout"); // Delete sector blocks /*u32 num = m_env.getMap().unloadUnusedData @@ -392,8 +395,7 @@ void Client::step(float dtime) } } } - - bool connected = connectedAndInitialized(); +#endif if(connected == false) { @@ -438,6 +440,67 @@ void Client::step(float dtime) Do stuff if connected */ + /* + Run Map's timers and unload unused data + */ + const float map_timer_and_unload_dtime = 5.25; + if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) + { + ScopeProfiler sp(&g_profiler, "Client: map timer and unload"); + core::list deleted_blocks; + m_env.getMap().timerUpdate(map_timer_and_unload_dtime, + g_settings.getFloat("client_unload_unused_data_timeout"), + &deleted_blocks); + + /*if(deleted_blocks.size() > 0) + dstream<<"Client: Unloaded "<::Iterator i = deleted_blocks.begin(); + core::list sendlist; + for(;;) + { + if(sendlist.size() == 255 || i == deleted_blocks.end()) + { + if(sendlist.size() == 0) + break; + /* + [0] u16 command + [2] u8 count + [3] v3s16 pos_0 + [3+6] v3s16 pos_1 + ... + */ + u32 replysize = 2+1+6*sendlist.size(); + SharedBuffer reply(replysize); + writeU16(&reply[0], TOSERVER_DELETEDBLOCKS); + reply[2] = sendlist.size(); + u32 k = 0; + for(core::list::Iterator + j = sendlist.begin(); + j != sendlist.end(); j++) + { + writeV3S16(&reply[2+1+6*k], *j); + k++; + } + m_con.Send(PEER_ID_SERVER, 1, reply, true); + + if(i == deleted_blocks.end()) + break; + + sendlist.clear(); + } + + sendlist.push_back(*i); + i++; + } + } + /* Handle environment */ @@ -453,23 +516,23 @@ void Client::step(float dtime) //TimeTaker envtimer("env step", m_device); // Step environment m_env.step(dtime); - - // Step active blocks + + /* + Handle active blocks + NOTE: These old objects are DEPRECATED. TODO: Remove + */ for(core::map::Iterator i = m_active_blocks.getIterator(); i.atEnd() == false; i++) { v3s16 p = i.getNode()->getKey(); - MapBlock *block = NULL; - try - { - block = m_env.getMap().getBlockNoCreate(p); - block->stepObjects(dtime, false, m_env.getDayNightRatio()); - } - catch(InvalidPositionException &e) - { - } + MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(p); + if(block == NULL) + continue; + + // Step MapBlockObjects + block->stepObjects(dtime, false, m_env.getDayNightRatio()); } /* @@ -1183,6 +1246,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) /* Read block objects + NOTE: Deprecated stuff here, TODO: Remove */ // Read active block count diff --git a/src/client.h b/src/client.h index 442eaef5..bd838fee 100644 --- a/src/client.h +++ b/src/client.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "jmutex.h" #include #include "clientobject.h" +#include "utility.h" // For IntervalLimiter struct MeshMakeData; @@ -306,11 +307,11 @@ private: void sendPlayerInfo(); float m_packetcounter_timer; - float m_delete_unused_sectors_timer; float m_connection_reinit_timer; float m_avg_rtt_timer; float m_playerpos_send_timer; float m_ignore_damage_timer; // Used after server moves player + IntervalLimiter m_map_timer_and_unload_interval; MeshUpdateThread m_mesh_update_thread; diff --git a/src/clientserver.h b/src/clientserver.h index 7972762c..35484fe7 100644 --- a/src/clientserver.h +++ b/src/clientserver.h @@ -37,7 +37,7 @@ enum ToClientCommand [0] u16 TOSERVER_INIT [2] u8 deployed version [3] v3s16 player's position + v3f(0,BS/2,0) floatToInt'd - ([4] u64 map seed (new as of 2011-02-27)) + [12] u64 map seed (new as of 2011-02-27) NOTE: The position in here is deprecated; position is explicitly sent afterwards diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 99bead6b..0213ede1 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -56,7 +56,7 @@ void set_default_settings() g_settings.setDefault("screenH", "600"); g_settings.setDefault("address", ""); g_settings.setDefault("random_input", "false"); - g_settings.setDefault("client_delete_unused_sectors_timeout", "1200"); + g_settings.setDefault("client_unload_unused_data_timeout", "1200"); g_settings.setDefault("enable_fog", "true"); g_settings.setDefault("new_style_water", "false"); g_settings.setDefault("new_style_leaves", "true"); @@ -94,7 +94,7 @@ void set_default_settings() g_settings.setDefault("max_block_generate_distance", "8"); g_settings.setDefault("time_send_interval", "20"); g_settings.setDefault("time_speed", "96"); - g_settings.setDefault("server_unload_unused_sectors_timeout", "60"); + g_settings.setDefault("server_unload_unused_data_timeout", "60"); g_settings.setDefault("server_map_save_interval", "60"); g_settings.setDefault("full_block_send_enable_min_time_from_building", "2.0"); //g_settings.setDefault("dungeon_rarity", "0.025"); diff --git a/src/environment.cpp b/src/environment.cpp index b52a46dd..ac69c8ae 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -660,14 +660,6 @@ void ServerEnvironment::step(float dtime) m_game_time_fraction_counter -= (float)inc_i; } - /* - Let map update it's timers - */ - { - //TimeTaker timer("Server m_map->timerUpdate()"); - m_map->timerUpdate(dtime); - } - /* Handle players */ @@ -1469,11 +1461,6 @@ void ClientEnvironment::step(float dtime) bool free_move = g_settings.getBool("free_move"); bool footprints = g_settings.getBool("footprints"); - { - //TimeTaker timer("Client m_map->timerUpdate()"); - m_map->timerUpdate(dtime); - } - // Get local player LocalPlayer *lplayer = getLocalPlayer(); assert(lplayer); @@ -1672,7 +1659,7 @@ void ClientEnvironment::step(float dtime) // Step object obj->step(dtime, this); - if(m_active_object_light_update_interval.step(dtime, 0.5)) + if(m_active_object_light_update_interval.step(dtime, 0.21)) { // Update lighting //u8 light = LIGHT_MAX; diff --git a/src/main.cpp b/src/main.cpp index 9fb17e21..65d6006e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,6 +27,33 @@ NOTE: Global locale is now set at initialization NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the hardware buffer (it is not freed automatically) +NOTE: A random to-do list saved here as documentation: +A list of "active blocks" in which stuff happens. (+=done) + + Add a never-resetted game timer to the server + + Add a timestamp value to blocks + + The simple rule: All blocks near some player are "active" + - Do stuff in real time in active blocks + + Handle objects + - Grow grass, delete leaves without a tree + - Spawn some mobs based on some rules + - Transform cobble to mossy cobble near water + - Run a custom script + - ...And all kinds of other dynamic stuff + + Keep track of when a block becomes active and becomes inactive + + When a block goes inactive: + + Store objects statically to block + + Store timer value as the timestamp + + When a block goes active: + + Create active objects out of static objects + - Simulate the results of what would have happened if it would have + been active for all the time + - Grow a lot of grass and so on + + Initially it is fine to send information about every active object + to every player. Eventually it should be modified to only send info + about the nearest ones. + + This was left to be done by the old system and it sends only the + nearest ones. + Old, wild and random suggestions that probably won't be done: ------------------------------------------------------------- @@ -73,9 +100,6 @@ SUGG: Make the amount of blocks sending to client and the total SUGG: Meshes of blocks could be split into 6 meshes facing into different directions and then only those drawn that need to be -SUGG: Calculate lighting per vertex to get a lighting effect like in - bartwe's game - SUGG: Background music based on cellular automata? http://www.earslap.com/projectslab/otomata @@ -90,6 +114,8 @@ SUGG: Make a system for pregenerating quick information for mapblocks, so or even generated. SUGG: Erosion simulation at map generation time + - This might be plausible if larger areas of map were pregenerated + without lighting (which is slow) - Simulate water flows, which would carve out dirt fast and then turn stone into gravel and sand and relocate it. - How about relocating minerals, too? Coal and gold in @@ -231,6 +257,7 @@ FIXME: Server sometimes goes into some infinite PeerNotFoundException loop * Fix the problem with the server constantly saving one or a few blocks? List the first saved block, maybe it explains. - It is probably caused by oscillating water + - TODO: Investigate if this still happens (this is a very old one) * Make a small history check to transformLiquids to detect and log continuous oscillations, in such detail that they can be fixed. @@ -238,42 +265,12 @@ FIXME: The new optimized map sending doesn't sometimes send enough blocks from big caves and such FIXME: Block send distance configuration does not take effect for some reason -SUGG: Map unloading based on sector reference is not very good, it keeps - unnecessary stuff in memory. I guess. Investigate this. - -TODO: When block is placed and it has param_type==CPT_FACEDIR_SIMPLE, set - the direction accordingly. - Environment: ------------ -TODO: A list of "active blocks" in which stuff happens. (+=done) - + Add a never-resetted game timer to the server - + Add a timestamp value to blocks - + The simple rule: All blocks near some player are "active" - - Do stuff in real time in active blocks - + Handle objects - TODO: Make proper hooks in here - - Grow grass, delete leaves without a tree - - Spawn some mobs based on some rules - - Transform cobble to mossy cobble near water - - Run a custom script - - ...And all kinds of other dynamic stuff - + Keep track of when a block becomes active and becomes inactive - + When a block goes inactive: - + Store objects statically to block - + Store timer value as the timestamp - + When a block goes active: - + Create active objects out of static objects - TODO: Make proper hooks in here - - Simulate the results of what would have happened if it would have - been active for all the time - - Grow a lot of grass and so on - + Initially it is fine to send information about every active object - to every player. Eventually it should be modified to only send info - about the nearest ones. - + This was left to be done by the old system and it sends only the - nearest ones. +TODO: Add proper hooks to when adding and removing active blocks + +TODO: Finish the ActiveBlockModifier stuff and use it for something Objects: -------- @@ -285,6 +282,7 @@ TODO: Get rid of MapBlockObjects and use only ActiveObjects SUGG: MovingObject::move and Player::move are basically the same. combine them. + - NOTE: This is a bit tricky because player has the sneaking ability - NOTE: Player::move is more up-to-date. - NOTE: There is a simple move implementation now in collision.{h,cpp} - NOTE: MovingObject will be deleted (MapBlockObject) @@ -303,42 +301,17 @@ TODO: Mineral and ground material properties TODO: Flowing water to actually contain flow direction information - There is a space for this - it just has to be implemented. -SUGG: Try out the notch way of generating maps, that is, make bunches - of low-res 3d noise and interpolate linearly. - -Mapgen v2 (the current one): -* Possibly add some kind of erosion and other stuff -* Better water generation (spread it to underwater caverns but don't - fill dungeons that don't touch big water masses) -* When generating a chunk and the neighboring chunk doesn't have mud - and stuff yet and the ground is fairly flat, the mud will flow to - the other chunk making nasty straight walls when the other chunk - is generated. Fix it. Maybe just a special case if the ground is - flat? -* Consider not updating this one and make a good mainly block-based - generator - -SUGG: Make two "modified states", one that forces the block to be saved at - the next save event, and one that makes the block to be saved at exit - time. - -TODO: Add a not_fully_generated flag to MapBlock, which would be set for - blocks that contain eg. trees from neighboring generations but haven't - been generated itself. This is required for the future generator. - Misc. stuff: ------------ -- Make sure server handles removing grass when a block is placed (etc) - - The client should not do it by itself -- Block cube placement around player's head -- Protocol version field -- Consider getting some textures from cisoun's texture pack - - Ask from Cisoun -- Make sure the fence implementation and data format is good - - Think about using same bits for material for fences and doors, for - example -- Finish the ActiveBlockModifier stuff and use it for something -- Move mineral to param2, increment map serialization version, add conversion +TODO: Make sure server handles removing grass when a block is placed (etc) + - The client should not do it by itself + - NOTE: I think nobody does it currently... +TODO: Block cube placement around player's head +TODO: Protocol version field +TODO: Think about using same bits for material for fences and doors, for + example +TODO: Move mineral to param2, increment map serialization version, add + conversion TODO: Add a per-sector database to store surface stuff as simple flags/values - Light? @@ -354,8 +327,6 @@ TODO: Restart irrlicht completely when coming back to main menu from game. TODO: Merge bahamada's audio stuff (clean patch available) -TODO: Merge spongie's chest/furnace direction (by hand) - TODO: Merge key configuration menu (no clean patch available) Making it more portable: @@ -373,9 +344,6 @@ Stuff to do after release: Doing currently: ---------------- -TODO: Use MapBlock::resetUsageTimer() in appropriate places - (on client and server) - ====================================================================== */ @@ -404,16 +372,12 @@ TODO: Use MapBlock::resetUsageTimer() in appropriate places #include #include -//#include #include #include "main.h" #include "common_irrlicht.h" #include "debug.h" -//#include "map.h" -//#include "player.h" #include "test.h" #include "server.h" -//#include "client.h" #include "constants.h" #include "porting.h" #include "gettime.h" @@ -422,8 +386,6 @@ TODO: Use MapBlock::resetUsageTimer() in appropriate places #include "config.h" #include "guiMainMenu.h" #include "mineral.h" -//#include "noise.h" -//#include "tile.h" #include "materials.h" #include "game.h" #include "keycode.h" diff --git a/src/map.cpp b/src/map.cpp index 2cf7bb2e..0f374169 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1386,8 +1386,15 @@ bool Map::dayNightDiffed(v3s16 blockpos) /* Updates usage timers */ -void Map::timerUpdate(float dtime) +void Map::timerUpdate(float dtime, float unload_timeout, + core::list *unloaded_blocks) { + bool save_before_unloading = (mapType() == MAPTYPE_SERVER); + + core::list sector_deletion_queue; + u32 deleted_blocks_count = 0; + u32 saved_blocks_count = 0; + core::map::Iterator si; si = m_sectors.getIterator(); @@ -1395,13 +1402,60 @@ void Map::timerUpdate(float dtime) { MapSector *sector = si.getNode()->getValue(); + bool all_blocks_deleted = true; + core::list blocks; sector->getBlocks(blocks); for(core::list::Iterator i = blocks.begin(); i != blocks.end(); i++) { - (*i)->incrementUsageTimer(dtime); + MapBlock *block = (*i); + + block->incrementUsageTimer(dtime); + + if(block->getUsageTimer() > unload_timeout) + { + v3s16 p = block->getPos(); + + // Save if modified + if(block->getModified() != MOD_STATE_CLEAN + && save_before_unloading) + { + saveBlock(block); + saved_blocks_count++; + } + + // Delete from memory + sector->deleteBlock(block); + + if(unloaded_blocks) + unloaded_blocks->push_back(p); + + deleted_blocks_count++; + } + else + { + all_blocks_deleted = false; + } } + + if(all_blocks_deleted) + { + sector_deletion_queue.push_back(si.getNode()->getKey()); + } + } + + // Finally delete the empty sectors + deleteSectors(sector_deletion_queue); + + if(deleted_blocks_count != 0) + { + PrintInfo(dstream); // ServerMap/ClientMap: + dstream<<"Unloaded "< &list) } } +#if 0 void Map::unloadUnusedData(float timeout, core::list *deleted_blocks) { @@ -1474,6 +1529,7 @@ void Map::unloadUnusedData(float timeout, //return sector_deletion_queue.getSize(); //return deleted_blocks_count; } +#endif void Map::PrintInfo(std::ostream &out) { @@ -1500,7 +1556,7 @@ void Map::transformLiquids(core::map & modified_blocks) */ v3s16 p0 = m_transforming_liquid.pop_front(); - MapNode n0 = getNode(p0); + MapNode n0 = getNodeNoEx(p0); // Don't deal with non-liquids if(content_liquid(n0.d) == false) @@ -1532,13 +1588,10 @@ void Map::transformLiquids(core::map & modified_blocks) }; for(u16 i=0; i<5; i++) { - try - { - bool from_top = (i==0); v3s16 p2 = p0 + dirs_from[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); if(content_liquid(n2.d)) { @@ -1572,10 +1625,6 @@ void Map::transformLiquids(core::map & modified_blocks) if(new_liquid_level > new_liquid_level_max) new_liquid_level_max = new_liquid_level; } - - }catch(InvalidPositionException &e) - { - } } //for /* @@ -1618,20 +1667,13 @@ void Map::transformLiquids(core::map & modified_blocks) }; for(u16 i=0; i<6; i++) { - try - { - v3s16 p2 = p0 + dirs[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); if(content_flowing_liquid(n2.d)) { m_transforming_liquid.push_back(p2); } - - }catch(InvalidPositionException &e) - { - } } } } @@ -1652,9 +1694,6 @@ void Map::transformLiquids(core::map & modified_blocks) }; for(u16 i=0; i<5; i++) { - try - { - bool to_bottom = (i == 0); // If liquid is at lowest possible height, it's not going @@ -1680,7 +1719,7 @@ void Map::transformLiquids(core::map & modified_blocks) v3s16 p2 = p0 + dirs_to[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); //dstream<<"[1] n2.param="<<(int)n2.param< & modified_blocks) // If n2_changed to bottom, don't flow anywhere else if(to_bottom && flowed && !is_source) break; - - }catch(InvalidPositionException &e) - { - } } loopcount++; @@ -1945,7 +1980,6 @@ ServerMap::~ServerMap() { if(m_map_saving_enabled) { - //save(false); // Save only changed parts save(true); dstream<resetUsageTimer(); // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && diff --git a/src/map.h b/src/map.h index 2fe74900..71101b8e 100644 --- a/src/map.h +++ b/src/map.h @@ -223,19 +223,23 @@ public: virtual void save(bool only_changed){assert(0);}; - // Server implements this + // Server implements this. + // Client leaves it as no-op. virtual void saveBlock(MapBlock *block){}; /* - Updates usage timers + Updates usage timers and unloads unused blocks and sectors. + Saves modified blocks before unloading on MAPTYPE_SERVER. */ - void timerUpdate(float dtime); + void timerUpdate(float dtime, float unload_timeout, + core::list *unloaded_blocks=NULL); // Deletes sectors and their blocks from memory // Takes cache into account // If deleted sector is in sector cache, clears cache void deleteSectors(core::list &list); - + +#if 0 /* Unload unused data = flush changed to disk and delete from memory, if usage timer of @@ -243,8 +247,9 @@ public: */ void unloadUnusedData(float timeout, core::list *deleted_blocks=NULL); +#endif - // For debug printing + // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: " virtual void PrintInfo(std::ostream &out); void transformLiquids(core::map & modified_blocks); diff --git a/src/server.cpp b/src/server.cpp index b65f0bdb..798f36ac 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -602,6 +602,9 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime, bool block_is_invalid = false; if(block != NULL) { + // Reset usage timer, this block will be of use in the future. + block->resetUsageTimer(); + // Block is dummy if data doesn't exist. // It means it has been not found from disk and not generated if(block->isDummy()) @@ -1297,12 +1300,21 @@ void Server::AsyncRunStep() } { - // Step environment - // This also runs Map's timers JMutexAutoLock lock(m_env_mutex); + // Step environment ScopeProfiler sp(&g_profiler, "Server: environment step"); m_env.step(dtime); } + + const float map_timer_and_unload_dtime = 5.15; + if(m_map_timer_and_unload_interval.step(dtime, map_timer_and_unload_dtime)) + { + JMutexAutoLock lock(m_env_mutex); + // Run Map's timers and unload unused data + ScopeProfiler sp(&g_profiler, "Server: map timer and unload"); + m_env.getMap().timerUpdate(map_timer_and_unload_dtime, + g_settings.getFloat("server_unload_unused_data_timeout")); + } /* Do background stuff @@ -1665,8 +1677,15 @@ void Server::AsyncRunStep() if(m_unsent_map_edit_queue.size() >= 4) disable_single_change_sending = true; + bool got_any_events = false; + + // We'll log the amount of each + Profiler prof; + while(m_unsent_map_edit_queue.size() != 0) { + got_any_events = true; + MapEditEvent* event = m_unsent_map_edit_queue.pop_front(); // Players far away from the change are stored here. @@ -1676,7 +1695,8 @@ void Server::AsyncRunStep() if(event->type == MEET_ADDNODE) { - dstream<<"Server: MEET_ADDNODE"<p, event->n, event->already_known_by_peer, &far_players, 5); @@ -1686,7 +1706,8 @@ void Server::AsyncRunStep() } else if(event->type == MEET_REMOVENODE) { - dstream<<"Server: MEET_REMOVENODE"<p, event->already_known_by_peer, &far_players, 5); @@ -1697,15 +1718,18 @@ void Server::AsyncRunStep() else if(event->type == MEET_BLOCK_NODE_METADATA_CHANGED) { dstream<<"Server: MEET_BLOCK_NODE_METADATA_CHANGED"<p); } else if(event->type == MEET_OTHER) { + prof.add("MEET_OTHER", 1); dstream<<"WARNING: Server: MEET_OTHER not implemented" <type)<= 1 && m_unsent_map_edit_queue.size() < 100) break;*/ } + + if(got_any_events) + { + dstream<<"Server: MapEditEvents:"< changed_blocks; - m_env.getMap().nodeMetadataStep(dtime, changed_blocks); - - // Use setBlockNotSent - - for(core::map::Iterator - i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - - for(core::map::Iterator - i = m_clients.getIterator(); - i.atEnd()==false; i++) - { - RemoteClient *client = i.getNode()->getValue(); - client->SetBlockNotSent(block->getPos()); - } - } - }*/ - /* Trigger emergethread (it somehow gets to a non-triggered but bysy state sometimes) @@ -1829,30 +1827,29 @@ void Server::AsyncRunStep() // Map JMutexAutoLock lock(m_env_mutex); - if(((ServerMap*)(&m_env.getMap()))->isSavingEnabled() == true) - { - // Unload unused data (delete from memory) - m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); - /*u32 deleted_count = m_env.getMap().unloadUnusedData( - g_settings.getFloat("server_unload_unused_sectors_timeout")); - */ - // Save only changed parts - m_env.getMap().save(true); + /*// Unload unused data (delete from memory) + m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ + /*u32 deleted_count = m_env.getMap().unloadUnusedData( + g_settings.getFloat("server_unload_unused_sectors_timeout")); + */ - /*if(deleted_count > 0) - { - dout_server<<"Server: Unloaded "< 0) + { + dout_server<<"Server: Unloaded "<clone(); diff --git a/src/server.h b/src/server.h index b88369dd..1da004da 100644 --- a/src/server.h +++ b/src/server.h @@ -534,6 +534,7 @@ private: float m_objectdata_timer; float m_emergethread_trigger_timer; float m_savemap_timer; + IntervalLimiter m_map_timer_and_unload_interval; // NOTE: If connection and environment are both to be locked, // environment shall be locked first.