aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPerttu Ahola <celeron55@gmail.com>2011-04-26 00:23:38 +0300
committerPerttu Ahola <celeron55@gmail.com>2011-04-26 00:23:38 +0300
commit28300953667b6a44efb5be6b2c612993de060636 (patch)
tree86b6a28085e34218ebe8d552f7993694a55366f2
parent42fb1ba676de762b033b943c4a2d82db6229d245 (diff)
downloadminetest-28300953667b6a44efb5be6b2c612993de060636.tar.gz
minetest-28300953667b6a44efb5be6b2c612993de060636.tar.bz2
minetest-28300953667b6a44efb5be6b2c612993de060636.zip
Optimized map saving and sending (server-side)
-rw-r--r--src/defaultsettings.cpp4
-rw-r--r--src/main.cpp3
-rw-r--r--src/map.cpp14
-rw-r--r--src/map.h35
-rw-r--r--src/mapchunk.h7
-rw-r--r--src/server.cpp168
-rw-r--r--src/server.h6
7 files changed, 175 insertions, 62 deletions
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index fc63856ba..1ba8c1194 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -62,8 +62,8 @@ void set_default_settings()
g_settings.setDefault("max_simultaneous_block_sends_per_client", "1");
//g_settings.setDefault("max_simultaneous_block_sends_per_client", "2");
g_settings.setDefault("max_simultaneous_block_sends_server_total", "4");
- g_settings.setDefault("max_block_send_distance", "7");
- g_settings.setDefault("max_block_generate_distance", "7");
+ g_settings.setDefault("max_block_send_distance", "8");
+ 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");
diff --git a/src/main.cpp b/src/main.cpp
index 51a407827..1f178ab6e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -219,6 +219,9 @@ SUGG: MovingObject::move and Player::move are basically the same.
- NOTE: Player::move is more up-to-date.
- NOTE: There is a simple move implementation now in collision.{h,cpp}
+SUGG: Server-side objects could be moved based on nodes to enable very
+ lightweight operation and simple AI
+
Map:
----
diff --git a/src/map.cpp b/src/map.cpp
index 9610b0b53..a5e230419 100644
--- a/src/map.cpp
+++ b/src/map.cpp
@@ -1792,7 +1792,8 @@ void Map::nodeMetadataStep(float dtime,
ServerMap::ServerMap(std::string savedir):
Map(dout_server),
- m_seed(0)
+ m_seed(0),
+ m_map_metadata_changed(true)
{
dstream<<__FUNCTION_NAME<<std::endl;
@@ -4797,12 +4798,17 @@ void ServerMap::save(bool only_changed)
dstream<<DTIME<<"ServerMap: Saving whole map, this can take time."
<<std::endl;
- saveMapMeta();
+ if(only_changed == false || m_map_metadata_changed)
+ {
+ saveMapMeta();
+ m_map_metadata_changed = false;
+ }
- // Disable saving chunk metadata file if chunks are disabled
+ // Disable saving chunk metadata if chunks are disabled
if(m_chunksize != 0)
{
- saveChunkMeta();
+ if(only_changed == false || anyChunkModified())
+ saveChunkMeta();
}
u32 sector_meta_count = 0;
diff --git a/src/map.h b/src/map.h
index 1cd021f52..77a006390 100644
--- a/src/map.h
+++ b/src/map.h
@@ -401,6 +401,35 @@ public:
}
return true;
}
+
+ /*
+ Returns true if any chunk is marked as modified
+ */
+ bool anyChunkModified()
+ {
+ for(core::map<v2s16, MapChunk*>::Iterator
+ i = m_chunks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ v2s16 p = i.getNode()->getKey();
+ MapChunk *chunk = i.getNode()->getValue();
+ if(chunk->isModified())
+ return true;
+ }
+ return false;
+ }
+
+ void setChunksNonModified()
+ {
+ for(core::map<v2s16, MapChunk*>::Iterator
+ i = m_chunks.getIterator();
+ i.atEnd()==false; i++)
+ {
+ v2s16 p = i.getNode()->getKey();
+ MapChunk *chunk = i.getNode()->getValue();
+ chunk->setModified(false);
+ }
+ }
/*
Chunks are generated by using these and makeChunk().
@@ -573,6 +602,12 @@ private:
s16 m_chunksize;
// Chunks
core::map<v2s16, MapChunk*> m_chunks;
+
+ /*
+ Metadata is re-written on disk only if this is true.
+ This is reset to false when written on disk.
+ */
+ bool m_map_metadata_changed;
};
/*
diff --git a/src/mapchunk.h b/src/mapchunk.h
index 1819fa13e..9860abad0 100644
--- a/src/mapchunk.h
+++ b/src/mapchunk.h
@@ -36,7 +36,8 @@ class MapChunk
{
public:
MapChunk():
- m_generation_level(GENERATED_NOT)
+ m_generation_level(GENERATED_NOT),
+ m_modified(true)
{
}
@@ -58,8 +59,12 @@ public:
is.read((char*)&m_generation_level, 1);
}
+ bool isModified(){ return m_modified; }
+ void setModified(bool modified){ m_modified = modified; }
+
private:
u8 m_generation_level;
+ bool m_modified;
};
#endif
diff --git a/src/server.cpp b/src/server.cpp
index 9c02389e2..c9c115abb 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -306,8 +306,15 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
{
DSTACK(__FUNCTION_NAME);
+ /*u32 timer_result;
+ TimeTaker timer("RemoteClient::GetNextBlocks", &timer_result);*/
+
// Increment timers
m_nearest_unsent_reset_timer += dtime;
+ m_nothing_to_send_pause_timer -= dtime;
+
+ if(m_nothing_to_send_pause_timer >= 0)
+ return;
// Won't send anything if already sending
if(m_blocks_sending.size() >= g_settings.getU16
@@ -338,8 +345,6 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
/*
Get the starting value of the block finder radius.
*/
- s16 last_nearest_unsent_d;
- s16 d_start;
if(m_last_center != center)
{
@@ -356,14 +361,14 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
//dstream<<"Resetting m_nearest_unsent_d"<<std::endl;
}
- last_nearest_unsent_d = m_nearest_unsent_d;
-
- d_start = m_nearest_unsent_d;
+ //s16 last_nearest_unsent_d = m_nearest_unsent_d;
+ s16 d_start = m_nearest_unsent_d;
- u16 maximum_simultaneous_block_sends_setting = g_settings.getU16
+ //dstream<<"d_start="<<d_start<<std::endl;
+
+ u16 max_simul_sends_setting = g_settings.getU16
("max_simultaneous_block_sends_per_client");
- u16 maximum_simultaneous_block_sends =
- maximum_simultaneous_block_sends_setting;
+ u16 max_simul_sends_usually = max_simul_sends_setting;
/*
Check the time from last addNode/removeNode.
@@ -374,10 +379,13 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
if(m_time_from_building < g_settings.getFloat(
"full_block_send_enable_min_time_from_building"))
{
- maximum_simultaneous_block_sends
+ max_simul_sends_usually
= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
}
+ /*
+ Number of blocks sending + number of blocks selected for sending
+ */
u32 num_blocks_selected = m_blocks_sending.size();
/*
@@ -394,6 +402,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
//dstream<<"Starting from "<<d_start<<std::endl;
+ bool sending_something = false;
+
for(s16 d = d_start; d <= d_max; d++)
{
//dstream<<"RemoteClient::SendBlocks(): d="<<d<<std::endl;
@@ -404,11 +414,11 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
update our d to it.
Else update m_nearest_unsent_d
*/
- if(m_nearest_unsent_d != last_nearest_unsent_d)
+ /*if(m_nearest_unsent_d != last_nearest_unsent_d)
{
d = m_nearest_unsent_d;
last_nearest_unsent_d = m_nearest_unsent_d;
- }
+ }*/
/*
Get the border/face dot coordinates of a "d-radiused"
@@ -430,25 +440,18 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
Also, don't send blocks that are already flying.
*/
- u16 maximum_simultaneous_block_sends_now =
- maximum_simultaneous_block_sends;
+ // Start with the usual maximum
+ u16 max_simul_dynamic = max_simul_sends_usually;
+ // If block is very close, allow full maximum
if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
- {
- maximum_simultaneous_block_sends_now =
- maximum_simultaneous_block_sends_setting;
- }
+ max_simul_dynamic = max_simul_sends_setting;
- // Limit is dynamically lowered when building
- if(num_blocks_selected
- >= maximum_simultaneous_block_sends_now)
- {
- /*dstream<<"Not sending more blocks. Queue full. "
- <<m_blocks_sending.size()
- <<std::endl;*/
+ // Don't select too many blocks for sending
+ if(num_blocks_selected >= max_simul_dynamic)
goto queue_full;
- }
-
+
+ // Don't send blocks that are currently being transferred
if(m_blocks_sending.find(p) != NULL)
continue;
@@ -476,37 +479,35 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
continue;
}
-#if 0
+#if 1
/*
If block is far away, don't generate it unless it is
- near ground level
-
- NOTE: We can't know the ground level this way with the
- new generator.
+ near ground level.
*/
- if(d > 4)
+ if(d >= 4)
{
- v2s16 p2d(p.X, p.Z);
- MapSector *sector = NULL;
- try
- {
- sector = server->m_env.getMap().getSectorNoGenerate(p2d);
- }
- catch(InvalidPositionException &e)
- {
- }
-
- if(sector != NULL)
- {
- // Get center ground height in nodes
- f32 gh = sector->getGroundHeight(
- v2s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2));
- // Block center y in nodes
- f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
- // If differs a lot, don't generate
- if(fabs(gh - y) > MAP_BLOCKSIZE*2)
- generate = false;
- }
+ #if 1
+ // Block center y in nodes
+ f32 y = (f32)(p.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE/2);
+ // Don't generate if it's very high or very low
+ if(y < -64 || y > 64)
+ generate = false;
+ #endif
+ #if 0
+ v2s16 p2d_nodes_center(
+ MAP_BLOCKSIZE*p.X,
+ MAP_BLOCKSIZE*p.Z);
+
+ // Get ground height in nodes
+ s16 gh = server->m_env.getServerMap().findGroundLevel(
+ p2d_nodes_center);
+
+ // If differs a lot, don't generate
+ if(fabs(gh - y) > MAP_BLOCKSIZE*2)
+ generate = false;
+ // Actually, don't even send it
+ //continue;
+ #endif
}
#endif
@@ -556,6 +557,20 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
v2s16 chunkpos = map->sector_to_chunk(p2d);
if(map->chunkNonVolatile(chunkpos) == false)
block_is_invalid = true;
+#if 1
+ /*
+ If block is not close, don't send it unless it is near
+ ground level.
+
+ Block is not near ground level if night-time mesh
+ doesn't differ from day-time mesh.
+ */
+ if(d >= 3)
+ {
+ if(block->dayNightDiffed() == false)
+ continue;
+ }
+#endif
}
/*
@@ -574,7 +589,8 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
*/
if(new_nearest_unsent_d == -1 || d < new_nearest_unsent_d)
{
- new_nearest_unsent_d = d;
+ if(generate == true)
+ new_nearest_unsent_d = d;
}
/*
@@ -612,6 +628,7 @@ void RemoteClient::GetNextBlocks(Server *server, float dtime,
dest.push_back(q);
num_blocks_selected += 1;
+ sending_something = true;
}
}
queue_full:
@@ -620,6 +637,24 @@ queue_full:
{
m_nearest_unsent_d = new_nearest_unsent_d;
}
+
+ if(sending_something == false)
+ {
+ m_nothing_to_send_counter++;
+ if(m_nothing_to_send_counter >= 3)
+ {
+ // Pause time in seconds
+ m_nothing_to_send_pause_timer = 2.0;
+ }
+ }
+ else
+ {
+ m_nothing_to_send_counter = 0;
+ }
+
+ /*timer_result = timer.stop(true);
+ if(timer_result != 0)
+ dstream<<"GetNextBlocks duration: "<<timer_result<<" (!=0)"<<std::endl;*/
}
void RemoteClient::SendObjectData(
@@ -3402,6 +3437,30 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id,
void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
{
DSTACK(__FUNCTION_NAME);
+
+ v3s16 p = block->getPos();
+
+#if 0
+ // Analyze it a bit
+ bool completely_air = true;
+ for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+ for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+ for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+ {
+ if(block->getNodeNoEx(v3s16(x0,y0,z0)).d != CONTENT_AIR)
+ {
+ completely_air = false;
+ x0 = y0 = z0 = MAP_BLOCKSIZE; // Break out
+ }
+ }
+
+ // Print result
+ dstream<<"Server: Sending block ("<<p.X<<","<<p.Y<<","<<p.Z<<"): ";
+ if(completely_air)
+ dstream<<"[completely air] ";
+ dstream<<std::endl;
+#endif
+
/*
Create a packet with the block in the right format
*/
@@ -3413,7 +3472,6 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver)
u32 replysize = 8 + blockdata.getSize();
SharedBuffer<u8> reply(replysize);
- v3s16 p = block->getPos();
writeU16(&reply[0], TOCLIENT_BLOCKDATA);
writeS16(&reply[2], p.X);
writeS16(&reply[4], p.Y);
diff --git a/src/server.h b/src/server.h
index cba5fc2ce..e9477ba53 100644
--- a/src/server.h
+++ b/src/server.h
@@ -250,6 +250,8 @@ public:
pending_serialization_version = SER_FMT_VER_INVALID;
m_nearest_unsent_d = 0;
m_nearest_unsent_reset_timer = 0.0;
+ m_nothing_to_send_counter = 0;
+ m_nothing_to_send_pause_timer = 0;
}
~RemoteClient()
{
@@ -350,6 +352,10 @@ private:
This is resetted by PrintInfo()
*/
u32 m_excess_gotblocks;
+
+ // CPU usage optimization
+ u32 m_nothing_to_send_counter;
+ float m_nothing_to_send_pause_timer;
};
class Server : public con::PeerHandler, public MapEventReceiver,