#
# 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
#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
#time_speed = 1440
#time_send_interval = 5
-#server_unload_unused_sectors_timeout = 60
+#server_unload_unused_data_timeout = 60
#server_map_save_interval = 60
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;
m_packetcounter.clear();
}
}
+
+ // Get connection status
+ bool connected = connectedAndInitialized();
+#if 0
{
/*
Delete unused sectors
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
}
}
}
-
- bool connected = connectedAndInitialized();
+#endif
if(connected == false)
{
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<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
*/
//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());
}
/*
/*
Read block objects
+ NOTE: Deprecated stuff here, TODO: Remove
*/
// Read active block count
#include "jmutex.h"
#include <ostream>
#include "clientobject.h"
+#include "utility.h" // For IntervalLimiter
struct MeshMakeData;
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;
[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
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");
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");
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
*/
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);
// 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;
NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the\r
hardware buffer (it is not freed automatically)\r
\r
+NOTE: A random to-do list saved here as documentation:\r
+A list of "active blocks" in which stuff happens. (+=done)\r
+ + Add a never-resetted game timer to the server\r
+ + Add a timestamp value to blocks\r
+ + The simple rule: All blocks near some player are "active"\r
+ - Do stuff in real time in active blocks\r
+ + Handle objects\r
+ - Grow grass, delete leaves without a tree\r
+ - Spawn some mobs based on some rules\r
+ - Transform cobble to mossy cobble near water\r
+ - Run a custom script\r
+ - ...And all kinds of other dynamic stuff\r
+ + Keep track of when a block becomes active and becomes inactive\r
+ + When a block goes inactive:\r
+ + Store objects statically to block\r
+ + Store timer value as the timestamp\r
+ + When a block goes active:\r
+ + Create active objects out of static objects\r
+ - Simulate the results of what would have happened if it would have\r
+ been active for all the time\r
+ - Grow a lot of grass and so on\r
+ + Initially it is fine to send information about every active object\r
+ to every player. Eventually it should be modified to only send info\r
+ about the nearest ones.\r
+ + This was left to be done by the old system and it sends only the\r
+ nearest ones.\r
+\r
Old, wild and random suggestions that probably won't be done:\r
-------------------------------------------------------------\r
\r
SUGG: Meshes of blocks could be split into 6 meshes facing into\r
different directions and then only those drawn that need to be\r
\r
-SUGG: Calculate lighting per vertex to get a lighting effect like in\r
- bartwe's game\r
-\r
SUGG: Background music based on cellular automata?\r
http://www.earslap.com/projectslab/otomata\r
\r
or even generated.\r
\r
SUGG: Erosion simulation at map generation time\r
+ - This might be plausible if larger areas of map were pregenerated\r
+ without lighting (which is slow)\r
- Simulate water flows, which would carve out dirt fast and\r
then turn stone into gravel and sand and relocate it.\r
- How about relocating minerals, too? Coal and gold in\r
* Fix the problem with the server constantly saving one or a few\r
blocks? List the first saved block, maybe it explains.\r
- It is probably caused by oscillating water\r
+ - TODO: Investigate if this still happens (this is a very old one)\r
* Make a small history check to transformLiquids to detect and log\r
continuous oscillations, in such detail that they can be fixed.\r
\r
from big caves and such\r
FIXME: Block send distance configuration does not take effect for some reason\r
\r
-SUGG: Map unloading based on sector reference is not very good, it keeps\r
- unnecessary stuff in memory. I guess. Investigate this.\r
-\r
-TODO: When block is placed and it has param_type==CPT_FACEDIR_SIMPLE, set\r
- the direction accordingly.\r
-\r
Environment:\r
------------\r
\r
-TODO: A list of "active blocks" in which stuff happens. (+=done)\r
- + Add a never-resetted game timer to the server\r
- + Add a timestamp value to blocks\r
- + The simple rule: All blocks near some player are "active"\r
- - Do stuff in real time in active blocks\r
- + Handle objects\r
- TODO: Make proper hooks in here\r
- - Grow grass, delete leaves without a tree\r
- - Spawn some mobs based on some rules\r
- - Transform cobble to mossy cobble near water\r
- - Run a custom script\r
- - ...And all kinds of other dynamic stuff\r
- + Keep track of when a block becomes active and becomes inactive\r
- + When a block goes inactive:\r
- + Store objects statically to block\r
- + Store timer value as the timestamp\r
- + When a block goes active:\r
- + Create active objects out of static objects\r
- TODO: Make proper hooks in here\r
- - Simulate the results of what would have happened if it would have\r
- been active for all the time\r
- - Grow a lot of grass and so on\r
- + Initially it is fine to send information about every active object\r
- to every player. Eventually it should be modified to only send info\r
- about the nearest ones.\r
- + This was left to be done by the old system and it sends only the\r
- nearest ones.\r
+TODO: Add proper hooks to when adding and removing active blocks\r
+\r
+TODO: Finish the ActiveBlockModifier stuff and use it for something\r
\r
Objects:\r
--------\r
\r
SUGG: MovingObject::move and Player::move are basically the same.\r
combine them.\r
+ - NOTE: This is a bit tricky because player has the sneaking ability\r
- NOTE: Player::move is more up-to-date.\r
- NOTE: There is a simple move implementation now in collision.{h,cpp}\r
- NOTE: MovingObject will be deleted (MapBlockObject)\r
TODO: Flowing water to actually contain flow direction information\r
- There is a space for this - it just has to be implemented.\r
\r
-SUGG: Try out the notch way of generating maps, that is, make bunches\r
- of low-res 3d noise and interpolate linearly.\r
-\r
-Mapgen v2 (the current one):\r
-* Possibly add some kind of erosion and other stuff\r
-* Better water generation (spread it to underwater caverns but don't\r
- fill dungeons that don't touch big water masses)\r
-* When generating a chunk and the neighboring chunk doesn't have mud\r
- and stuff yet and the ground is fairly flat, the mud will flow to\r
- the other chunk making nasty straight walls when the other chunk\r
- is generated. Fix it. Maybe just a special case if the ground is\r
- flat?\r
-* Consider not updating this one and make a good mainly block-based\r
- generator\r
-\r
-SUGG: Make two "modified states", one that forces the block to be saved at\r
- the next save event, and one that makes the block to be saved at exit\r
- time.\r
-\r
-TODO: Add a not_fully_generated flag to MapBlock, which would be set for\r
- blocks that contain eg. trees from neighboring generations but haven't\r
- been generated itself. This is required for the future generator.\r
-\r
Misc. stuff:\r
------------\r
-- Make sure server handles removing grass when a block is placed (etc)\r
- - The client should not do it by itself\r
-- Block cube placement around player's head\r
-- Protocol version field\r
-- Consider getting some textures from cisoun's texture pack\r
- - Ask from Cisoun\r
-- Make sure the fence implementation and data format is good\r
- - Think about using same bits for material for fences and doors, for\r
- example\r
-- Finish the ActiveBlockModifier stuff and use it for something\r
-- Move mineral to param2, increment map serialization version, add conversion\r
+TODO: Make sure server handles removing grass when a block is placed (etc)\r
+ - The client should not do it by itself\r
+ - NOTE: I think nobody does it currently...\r
+TODO: Block cube placement around player's head\r
+TODO: Protocol version field\r
+TODO: Think about using same bits for material for fences and doors, for\r
+ example\r
+TODO: Move mineral to param2, increment map serialization version, add\r
+ conversion\r
\r
TODO: Add a per-sector database to store surface stuff as simple flags/values\r
- Light?\r
\r
TODO: Merge bahamada's audio stuff (clean patch available)\r
\r
-TODO: Merge spongie's chest/furnace direction (by hand)\r
-\r
TODO: Merge key configuration menu (no clean patch available)\r
\r
Making it more portable:\r
Doing currently:\r
----------------\r
\r
-TODO: Use MapBlock::resetUsageTimer() in appropriate places\r
- (on client and server)\r
-\r
======================================================================\r
\r
*/\r
\r
#include <iostream>\r
#include <fstream>\r
-//#include <jmutexautolock.h>\r
#include <locale.h>\r
#include "main.h"\r
#include "common_irrlicht.h"\r
#include "debug.h"\r
-//#include "map.h"\r
-//#include "player.h"\r
#include "test.h"\r
#include "server.h"\r
-//#include "client.h"\r
#include "constants.h"\r
#include "porting.h"\r
#include "gettime.h"\r
#include "config.h"\r
#include "guiMainMenu.h"\r
#include "mineral.h"\r
-//#include "noise.h"\r
-//#include "tile.h"\r
#include "materials.h"\r
#include "game.h"\r
#include "keycode.h"\r
/*
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();
{
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;
}
}
}
}
+#if 0
void Map::unloadUnusedData(float timeout,
core::list<v3s16> *deleted_blocks)
{
//return sector_deletion_queue.getSize();
//return deleted_blocks_count;
}
+#endif
void Map::PrintInfo(std::ostream &out)
{
*/
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)
};
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))
{
if(new_liquid_level > new_liquid_level_max)
new_liquid_level_max = new_liquid_level;
}
-
- }catch(InvalidPositionException &e)
- {
- }
} //for
/*
};
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)
- {
- }
}
}
}
};
for(u16 i=0; i<5; i++)
{
- try
- {
-
bool to_bottom = (i == 0);
// If liquid is at lowest possible height, it's not going
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))
// If n2_changed to bottom, don't flow anywhere else
if(to_bottom && flowed && !is_source)
break;
-
- }catch(InvalidPositionException &e)
- {
- }
}
loopcount++;
{
if(m_map_saving_enabled)
{
- //save(false);
// Save only changed parts
save(true);
dstream<<DTIME<<"Server: saved map to "<<m_savedir<<std::endl;
/*
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");
{
continue;
}
+
+ // Okay, this block will be drawn. Reset usage timer.
+ block->resetUsageTimer();
// This is ugly (spherical distance limit?)
/*if(m_control.range_all == false &&
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
*/
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);
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())
}
{
- // 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
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.
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);
}
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);
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;
}
if(count >= 1 && m_unsent_map_edit_queue.size() < 100)
break;*/
}
+
+ if(got_any_events)
+ {
+ dstream<<"Server: MapEditEvents:"<<std::endl;
+ prof.print(dstream);
+ }
+
}
/*
}
}
- /*
- 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)
// 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);
}
}
}
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();
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.