map unloading is now a whole lot better

This commit is contained in:
Perttu Ahola 2011-06-27 00:27:17 +03:00
parent 3fccc67eb7
commit dd22ea051a
11 changed files with 273 additions and 211 deletions

@ -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

@ -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)
{
@ -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<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

@ -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;

@ -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

@ -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");

@ -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;

@ -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"

@ -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);

@ -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);
}
}
/*
@ -1765,39 +1796,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);
/*if(deleted_count > 0)
{
// 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"));
*/
dout_server<<"Server: Unloaded "<<deleted_count
<<" blocks from memory"<<std::endl;
}*/
// Save only changed parts
m_env.getMap().save(true);
/*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);
}
// 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();

@ -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.