aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--minetest.conf.example8
-rw-r--r--src/client.cpp96
-rw-r--r--src/client.h3
-rw-r--r--src/clientserver.h2
-rw-r--r--src/defaultsettings.cpp4
-rw-r--r--src/environment.cpp15
-rw-r--r--src/main.cpp124
-rw-r--r--src/map.cpp99
-rw-r--r--src/map.h15
-rw-r--r--src/server.cpp115
-rw-r--r--src/server.h1
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 &&
diff --git a/src/map.h b/src/map.h
index 2fe749007..71101b8e4 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<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.