diff options
author | Perttu Ahola <celeron55@gmail.com> | 2011-06-27 00:27:17 +0300 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2011-06-27 00:27:17 +0300 |
commit | dd22ea051a643a1ca2657958c8552849dc1ffa36 (patch) | |
tree | fa9047294f1463270995277c6f4b948ae79b17f6 | |
parent | 3fccc67eb7c530c280e9b496e22288ffa772152d (diff) | |
download | minetest-dd22ea051a643a1ca2657958c8552849dc1ffa36.tar.gz minetest-dd22ea051a643a1ca2657958c8552849dc1ffa36.tar.bz2 minetest-dd22ea051a643a1ca2657958c8552849dc1ffa36.zip |
map unloading is now a whole lot better
-rw-r--r-- | minetest.conf.example | 8 | ||||
-rw-r--r-- | src/client.cpp | 96 | ||||
-rw-r--r-- | src/client.h | 3 | ||||
-rw-r--r-- | src/clientserver.h | 2 | ||||
-rw-r--r-- | src/defaultsettings.cpp | 4 | ||||
-rw-r--r-- | src/environment.cpp | 15 | ||||
-rw-r--r-- | src/main.cpp | 124 | ||||
-rw-r--r-- | src/map.cpp | 99 | ||||
-rw-r--r-- | src/map.h | 15 | ||||
-rw-r--r-- | src/server.cpp | 115 | ||||
-rw-r--r-- | src/server.h | 1 |
11 files changed, 272 insertions, 210 deletions
diff --git a/minetest.conf.example b/minetest.conf.example index 6e8a82bac..f94c8dee5 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 449b0c2f2..585fce11c 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<v3s16> 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) { @@ -439,6 +441,67 @@ void Client::step(float dtime) */ /* + 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<v3s16> 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 "<<deleted_blocks.size() + <<" unused blocks"<<std::endl;*/ + + /* + Send info to server + NOTE: This loop is intentionally iterated the way it is. + */ + + core::list<v3s16>::Iterator i = deleted_blocks.begin(); + core::list<v3s16> 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<u8> reply(replysize); + writeU16(&reply[0], TOSERVER_DELETEDBLOCKS); + reply[2] = sendlist.size(); + u32 k = 0; + for(core::list<v3s16>::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<v3s16, bool>::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 442eaef5d..bd838fee0 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 <ostream> #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 7972762c0..35484fe76 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 99bead6b0..0213ede1f 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 b52a46dde..ac69c8ae2 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -661,14 +661,6 @@ void ServerEnvironment::step(float dtime) } /* - Let map update it's timers - */ - { - //TimeTaker timer("Server m_map->timerUpdate()"); - m_map->timerUpdate(dtime); - } - - /* Handle players */ for(core::list<Player*>::Iterator i = m_players.begin(); @@ -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 9fb17e211..65d6006e3 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 <iostream>
#include <fstream>
-//#include <jmutexautolock.h>
#include <locale.h>
#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 2cf7bb2e5..0f3741691 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<v3s16> *unloaded_blocks) { + bool save_before_unloading = (mapType() == MAPTYPE_SERVER); + + core::list<v2s16> sector_deletion_queue; + u32 deleted_blocks_count = 0; + u32 saved_blocks_count = 0; + core::map<v2s16, MapSector*>::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<MapBlock*> blocks; sector->getBlocks(blocks); for(core::list<MapBlock*>::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 "<<deleted_blocks_count + <<" blocks from memory"; + if(save_before_unloading) + dstream<<", of which "<<saved_blocks_count<<" were written"; + dstream<<"."<<std::endl; } } @@ -1420,6 +1474,7 @@ void Map::deleteSectors(core::list<v2s16> &list) } } +#if 0 void Map::unloadUnusedData(float timeout, core::list<v3s16> *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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & 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<v3s16, MapBlock*> & modified_blocks) v3s16 p2 = p0 + dirs_to[i]; - MapNode n2 = getNode(p2); + MapNode n2 = getNodeNoEx(p2); //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl; if(content_liquid(n2.d)) @@ -1746,10 +1785,6 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & 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<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl; @@ -2104,11 +2138,15 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data, /* NOTE: Lighting and object adding shouldn't really be here, but lighting is a bit tricky to move properly to makeBlock. - TODO: Do this the right way anyway. + TODO: Do this the right way anyway, that is, move it to makeBlock. + - There needs to be some way for makeBlock to report back if + the lighting update is going further down because of the + new block blocking light */ /* Update lighting + NOTE: This takes ~60ms, TODO: Investigate why */ { TimeTaker t("finishBlockMake lighting update"); @@ -3418,6 +3456,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) { continue; } + + // Okay, this block will be drawn. Reset usage timer. + block->resetUsageTimer(); // This is ugly (spherical distance limit?) /*if(m_control.range_all == false && @@ -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<v3s16> *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<v2s16> &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<v3s16> *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<v3s16, MapBlock*> & modified_blocks); diff --git a/src/server.cpp b/src/server.cpp index b65f0bdb5..798f36ac1 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"<<std::endl; + //dstream<<"Server: MEET_ADDNODE"<<std::endl; + prof.add("MEET_ADDNODE", 1); if(disable_single_change_sending) sendAddNode(event->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"<<std::endl; + //dstream<<"Server: MEET_REMOVENODE"<<std::endl; + prof.add("MEET_REMOVENODE", 1); if(disable_single_change_sending) sendRemoveNode(event->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"<<std::endl; + prof.add("MEET_BLOCK_NODE_METADATA_CHANGED", 1); setBlockNotSent(event->p); } else if(event->type == MEET_OTHER) { + prof.add("MEET_OTHER", 1); dstream<<"WARNING: Server: MEET_OTHER not implemented" <<std::endl; } else { + prof.add("unknown", 1); dstream<<"WARNING: Server: Unknown MapEditEvent " <<((u32)event->type)<<std::endl; } @@ -1743,6 +1767,13 @@ void Server::AsyncRunStep() if(count >= 1 && m_unsent_map_edit_queue.size() < 100) break;*/ } + + if(got_any_events) + { + dstream<<"Server: MapEditEvents:"<<std::endl; + prof.print(dstream); + } + } /* @@ -1766,39 +1797,6 @@ void Server::AsyncRunStep() } /* - Step node metadata - TODO: Move to ServerEnvironment and utilize active block stuff - */ - /*{ - //TimeTaker timer("Step node metadata"); - - JMutexAutoLock envlock(m_env_mutex); - JMutexAutoLock conlock(m_con_mutex); - - ScopeProfiler sp(&g_profiler, "Server: stepping node metadata"); - - core::map<v3s16, MapBlock*> changed_blocks; - m_env.getMap().nodeMetadataStep(dtime, changed_blocks); - - // Use setBlockNotSent - - for(core::map<v3s16, MapBlock*>::Iterator - i = changed_blocks.getIterator(); - i.atEnd() == false; i++) - { - MapBlock *block = i.getNode()->getValue(); - - for(core::map<u16, RemoteClient*>::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 "<<deleted_count - <<" blocks from memory"<<std::endl; - }*/ + // Save only changed parts + m_env.getMap().save(true); - // Save players - m_env.serializePlayers(m_mapsavedir); - - // Save environment metadata - m_env.saveMeta(m_mapsavedir); - } + /*if(deleted_count > 0) + { + dout_server<<"Server: Unloaded "<<deleted_count + <<" blocks from memory"<<std::endl; + }*/ + + // Save players + m_env.serializePlayers(m_mapsavedir); + + // Save environment metadata + m_env.saveMeta(m_mapsavedir); } } } @@ -3336,7 +3333,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) void Server::onMapEditEvent(MapEditEvent *event) { - dstream<<"Server::onMapEditEvent()"<<std::endl; + //dstream<<"Server::onMapEditEvent()"<<std::endl; if(m_ignore_map_edit_events) return; MapEditEvent *e = event->clone(); diff --git a/src/server.h b/src/server.h index b88369ddf..1da004da5 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. |